我有一个C ++函数,如下所示:
template <class T> void MyClass::set(T value) {
if (std::is_same<T, std::string>::value) {
stringValue_ = value;
} else if (std::is_same<T, int>::value) {
intValue_ = value;
}
}
但是,我收到了编译错误。显然它认为T的类型总是一个std :: string:
assigning to 'int' from incompatible type 'std::__cxx11::basic_string<char>'
此外,当我尝试将值转换为int(int)值时,我得到了转换错误。此函数的整个要点是获取模板参数值,然后根据参数的实际类型将其分配给类的正确变量。请告诉我我在这里犯的错误或错误。
答案 0 :(得分:7)
您无法以您尝试的方式投射模板参数:
template <class T> void MyClass::set(T value) {
if (std::is_same<T, std::string>::value) {
stringValue_ = value;
} else if (std::is_same<T, int>::value) {
intValue_ = value;
}
}
这里的关键概念是模板函数在实例化时完整地扩展 。
如果说,对于给定的模板实例,T
模板参数是一个整数。然后,该模板大致以下列方式实例化:
void MyClass::set(int value)
{
if (false)
{
stringValue_=value;
}
您在此尝试将stringValue
(可能是std::string
)设置为int
,并不会非常成功。仅仅因为if
条件为假,就不会使这段代码消失。它仍然必须是有效的C ++,即使它永远不会被执行,这也不是有效的C ++。这是编译错误的解释。
最新的C ++ 17标准中的一些功能将使这些类型的构造实际上成为可能。但是,预解决这类问题的一般方法是使用模板专业化:
template<typename T> void MyClass::set(T value);
template<> void MyClass::set<int>(int value)
{
intValue_=value;
}
template<> void MyClass::set<std::string>(std::string value)
{
stringValue_=value;
}
或者,完全忘记模板,只需定义两个单独的set()
方法。
答案 1 :(得分:3)
编译器错误的原因是if
语句的两个分支都将使用模板进行实例化。这显然是一个错误,因为如果T = int
没有赋值运算符std::string
。 C ++ 17引入了一种在编译时忽略其中一个分支的方法,称为if constexpr
:
template <class T> void MyClass::set(T value) {
if constexpr (std::is_same<T, std::string>::value) {
stringValue_ = value;
} else if (std::is_same<T, int>::value) {
intValue_ = value;
}
}
但实际上,不要在这里使用模板(也不要在这里使用SFINAE!)。只需使用旧的函数重载。
class MyClass
{
std::string stringValue_;
int intValue_;
public:
void set(int);
void set(std::string);
};
void MyClass::set(int value) {
intValue_ = value;
}
void MyClass::set(std::string value) {
stringValue_ = value;
}
有人可能会说,如果你试图涵盖可以相互转换的各种类型,SFINAE实际上是必要的。
class MyClass
{
std::string stringValue_;
int intValue_;
public:
template < typename T, typename std::enable_if< std::is_arithmetic<T>::value, void** >::type = nullptr >
void set(T value) {
intValue_ = value;
}
template < typename T, typename std::enable_if< std::is_same<T,std::string>::value, void** >::type = nullptr >
void set(T value) {
stringValue_ = value;
}
};