说你有这样的课程:
template <typename T>
class MyClass {
public:
void doSomething();
};
在一个方法中,是否有任何方法可以根据类型具有不同的行为:
template <typename T> MyClass::doSomething() {
//this is what I want:
std::string value = "17";
if(T == int) {
int myInt = atoi(value.c_str());
} else if(T == std::string) {
std::string myString = value;
}
}
有没有简单的方法来实现这一点?
我知道我可以编写一个包装器类,它提供一个带std::string
的构造函数,所以我可以使用类似的东西:
T myVar(value);
但如果使用像int
之类的简单类型,那将会浪费更多资源,我也想知道if-else-statement能够执行不同的操作。
我会感谢你的回答。 的问候,
tagelicht
答案 0 :(得分:4)
在C ++ 17中,您可以使用if constexpr(...)
:
template <typename T> MyClass::doSomething() {
//this is what I want:
std::string value = "17";
if constexpr(std::is_same_v<T, int>) {
int myInt = atoi(value.c_str());
} else constexpr(std::is_same_v<T, std::string>) {
std::string myString = value;
}
}
在C ++ 14中,您可以非常轻松地实现自己的static_if
。我在CppCon 2016和Meeting C ++ 2016上给出了a tutorial talk。
template <typename T> MyClass::doSomething() {
//this is what I want:
std::string value = "17";
static_if(std::is_same_v<T, int>)
.then([&](auto) {
int myInt = atoi(value.c_str());
})
.else_if(std::is_same_v<T, std::string>)
.then([&](auto) {
std::string myString = value;
})();
}
在C ++ 11中,您可能希望使用函数重载或模板专门化。前的示例(在评论中更新了Jarod42的建议):
template <typename> struct tag { };
void call_dispatch(...) { } // lowest priority
void call_dispatch(tag<std::string>)
{
std::string myString = value;
}
void call_dispatch(tag<int>)
{
int myInt = atoi(value.c_str());
}
用法:
template <typename T> MyClass::doSomething() {
//this is what I want:
std::string value = "17";
call_dispatch(tag<T>{});
}
答案 1 :(得分:3)
尚未举例说明的两种方法是1)标签调度和2)模板专业化
我们这样做的方法是将一些空的模板化结构定义为轻量级“标记”类型:
template <typename T>
class MyClass {
public:
void doSomething();
private:
// tag for dispatch
template<class U>
struct doSomethingTag{};
...然后定义需要对该标记进行特化的辅助函数:
void doSomethingHelper(doSomethingTag<std::string>, std::string value);
void doSomethingHelper(doSomethingTag<int>, std::string value);
};
然后我们可以使用主入口点(doSomething
)作为调用专用助手函数的方法:
template <typename T>
void MyClass<T>::doSomething() {
//dispatch to helper function
doSomethingHelper(doSomethingTag<T>{}, "17");
}
辅助函数如下所示:
template <typename T>
void MyClass<T>::doSomethingHelper(doSomethingTag<std::string>, std::string value)
{
int myInt = atoi(value.c_str());
}
template <typename T>
void MyClass<T>::doSomethingHelper(doSomethingTag<int>, std::string value)
{
std::string myString = value;
}
这会导致标签结构的无开销,因为辅助函数实际上并不使用tag参数,因此它将被优化掉。如果不是,则构造结构的开销是1字节。 (注:Vittorio Romeo hinted at this in his answer,但他称之为“功能超载”)
只要你完全专注它,你就可以“专门化”你的功能模板(指定类的类型!):
专业化的语法看起来有点奇怪,因为我们将角括号保持为空:<>
:
template<>
void MyClass<int>::doSomething() {
//dispatch to helper function
std::string value = "17";
int myInt = atoi(value.c_str());
}
template <>
void MyClass<std::string>::doSomething()
{
std::string value = "17";
std::string myString = value;
}
这使您可以保留较小的班级:
template <typename T>
class MyClass {
public:
void doSomething();
};
在你给出的具体例子中,我更喜欢模板专业化。但是,您经常需要进行某种部分特化,这对于成员函数来说非常奇怪,因此通常首选标记调度。
使用C ++ 17,使用constexpr if绝对可以让生活更轻松。
答案 2 :(得分:2)
这个怎么样:
#include <type_traits>
template <typename T> MyClass::doSomething() {
//this is what I want:
std::string value = "17";
if(std::is_same<T,int>::value) {
int myInt = atoi(value.c_str());
} else if(std::is_same<T,std::string>::value) {
std::string myString = value;
}
}
这是C ++ 11。使用constexpr if
的C ++ 17可以使它更好。这里存在的问题是你必须转换非隐式可转换的值。例如,必须将std::string
的返回强制转换为int才能进行编译。