use*_*354 2 c++ generics parameters templates types
我有一个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;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我收到了编译器错误.显然它认为T的类型总是一个std :: string:
assigning to 'int' from incompatible type 'std::__cxx11::basic_string<char>'
Run Code Online (Sandbox Code Playgroud)
另外,当我尝试将值转换为int(int)值时,我会得到转换错误.此函数的整个要点是接受模板参数值,然后根据参数的实际类型将其分配给类的正确变量.请告诉我我在这里犯的错误或错误.
您无法以您尝试的方式强制转换模板参数:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
这里的关键概念是模板函数在实例化时完整地扩展.
如果说,对于给定的模板实例,T模板参数是整数.然后,该模板大致以下列方式实例化:
void MyClass::set(int value)
{
if (false)
{
stringValue_=value;
}
Run Code Online (Sandbox Code Playgroud)
在这里您尝试设置stringValue,这想必std::string,到int,不会是非常成功的.仅仅因为if条件是错误的,不会使这段代码消失.它仍然必须是有效的C++,即使它永远不会被执行,这也不是有效的C++.这是编译错误的解释.
最新的C++ 17标准中的一些功能将使这些类型的构造实际上成为可能.但是,预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;
}
Run Code Online (Sandbox Code Playgroud)
或者,完全忘记模板,只需定义两个单独的set()方法.
编译器错误的原因是if语句的两个分支都将使用模板进行实例化。这显然是一个错误,因为如果T = int没有赋值运算符 to 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;
}
}
Run Code Online (Sandbox Code Playgroud)
但实际上,不要在这里使用模板(也不要在这里使用 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;
}
Run Code Online (Sandbox Code Playgroud)
有人可能会争辩说,如果您试图涵盖可相互转换的整个类型范围,则 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;
}
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3594 次 |
| 最近记录: |