我试图根据类模板参数确定调用哪个版本的成员函数。我试过这个:
#include <iostream>
#include <type_traits>
template<typename T>
struct Point
{
void MyFunction(typename std::enable_if<std::is_same<T, int>::value, T >::type* = 0)
{
std::cout << "T is int." << std::endl;
}
void MyFunction(typename std::enable_if<!std::is_same<T, int>::value, float >::type* = 0)
{
std::cout << "T is not int." << std::endl;
}
};
int main()
{
Point<int> intPoint;
intPoint.MyFunction();
Point<float> floatPoint;
floatPoint.MyFunction();
}
我认为是“如果T是int则使用第一个MyFunction,如果T不是int则使用第二个MyFunction,但是我得到编译器错误”错误:'struct std :: enable_if'中没有名为'type'的类型谁能指出我在这里做错了什么?
enable_if
因为有效 替换模板参数会导致错误,以及从重载决策集中删除替换,并且编译器仅考虑其他可行的重载。
在您的示例中,实例化成员函数时不会发生替换,因为模板参数 T
当时已经知道了。实现您正在尝试的最简单的方法是创建一个默认的虚拟模板参数 T
并用它来执行SFINAE。
template<typename T>
struct Point
{
template<typename U = T>
typename std::enable_if<std::is_same<U, int>::value>::type
MyFunction()
{
std::cout << "T is int." << std::endl;
}
template<typename U = T>
typename std::enable_if<std::is_same<U, float>::value>::type
MyFunction()
{
std::cout << "T is not int." << std::endl;
}
};
编辑:
正如HostileFork在评论中提到的那样,原始示例使用户可以明确指定成员函数的模板参数并获得不正确的结果。以下内容应防止编译成员函数的显式特化。
template<typename T>
struct Point
{
template<typename... Dummy, typename U = T>
typename std::enable_if<std::is_same<U, int>::value>::type
MyFunction()
{
static_assert(sizeof...(Dummy)==0, "Do not specify template arguments!");
std::cout << "T is int." << std::endl;
}
template<typename... Dummy, typename U = T>
typename std::enable_if<std::is_same<U, float>::value>::type
MyFunction()
{
static_assert(sizeof...(Dummy)==0, "Do not specify template arguments!");
std::cout << "T is not int." << std::endl;
}
};
一个简单的解决方案是使用委托给工人 私人的 功能:
template<typename T>
struct Point
{
void MyFunction()
{
worker(static_cast<T*>(0)); //pass null argument of type T*
}
private:
void worker(int*)
{
std::cout << "T is int." << std::endl;
}
template<typename U>
void worker(U*)
{
std::cout << "T is not int." << std::endl;
}
};
什么时候 T
是 int
, 首先 worker
函数将被调用,因为 static_cast<T*>(0)
原来是类型 int*
。在所有其他情况下,将调用worker的模板版本。
enable_if
只适用于 推导 函数模板参数或专用类模板参数。你正在做什么不起作用,因为很明显是固定的 T = int
,第二个宣言是错误的。
这是如何做到的:
template <typename T>
void MyFreeFunction(Point<T> const & p,
typename std::enable_if<std::is_same<T, int>::value>::type * = NULL)
{
std::cout << "T is int" << std::endl;
}
// etc.
int main()
{
Point<int> ip;
MyFreeFunction(ip);
}
另一种选择是专业化 Point
适用于各种类型 T
,或将上述自由函数放入嵌套的成员模板包装器中(这可能是更“正确”的解决方案)。
根据Praetorian的建议(但不改变函数的返回类型),这似乎有效:
#include <iostream>
#include <type_traits>
template<typename T>
struct Point
{
template<typename U = T>
void MyFunction(typename std::enable_if<std::is_same<U, int>::value, U >::type* = 0)
{
std::cout << "T is int." << std::endl;
}
template<typename U = T>
void MyFunction(typename std::enable_if<!std::is_same<U, int>::value, float >::type* = 0)
{
std::cout << "T is not int." << std::endl;
}
};
int main()
{
Point<int> intPoint;
intPoint.MyFunction();
Point<float> floatPoint;
floatPoint.MyFunction();
}
点模板可以仅使用int或float作为模板参数T进行实例化。
回答这个问题:这里的worker()完全取决于method()调用的模板参数,但你仍然可以控制类型。
template<typename T>
struct Point
{
static_assert (
std::is_same<T, int>() ||
std::is_same<T, float>()
);
template<typename U>
void method(U x_, U y_)
{
if constexpr (std::is_same<T, U>()) {
worker(x_, y_);
return;
}
// else
worker(
static_cast<T>(x_),
static_cast<T>(y_)
);
return ;
}
private:
mutable T x{}, y{};
void worker(T x_, T y_)
{
// nothing but T x, T y
}
};
当worker()当然会工作,即使它被声明为静态。出于某些正当理由。对上述内容的其他扩展很少(也很简单),但让我们坚持回答。