我是模板的新手,我正在尝试使用它们,以避免重复非常相似的功能.
在下面的例子中,我做了一个简单而小巧的工作示例来说明我的问题.
特别是,我有两个struct("solo"和"duo").这些结构有一个共同的成员(a),其中一个有一个特定的成员(b).
然后我有一个模板函数,可以采取结构和打印成员...并且我希望它只能在结构类型为"duo"时才能打印成员b.
我这样做(使用std :: is_same_v)它不会编译.我读到可以使用专业化这样做,但我想知道是否有更优雅的方式?因为那时我有失去模板优势的感觉......但是我可能还没有获得模板的强大功能以及如何使用它们.
非常感谢您的帮助!
#include <iostream>
#include <string>
#include <type_traits>
struct solo{
int a;
};
struct duo : solo{
int b;
};
template<class T>
void function(T test){
std::cout<< std::to_string(test.a);
if(std::is_same<T, duo>::value) std::cout<< std::to_string(test.b);
}
int main()
{
solo testS;
testS.a = 1;
function(testS);
}
Run Code Online (Sandbox Code Playgroud)
通过 C++17 中的引入,constexpr if(cond)您可以实现您的目标。constexpr if(cond)在编译时评估,因此您可以根据参数的类型选择您想要执行的操作。以下片段提供了一个说明。
#include <iostream>
#include <string>
#include <type_traits>
struct solo{
int a;
};
struct duo : solo{
int b;
};
template<class T>
void function(T test){
if constexpr (std::is_same<T, duo>::value)
std::cout<< std::to_string(test.b)<<"\n";
else if constexpr (std::is_same<T, solo>::value)
std::cout<< std::to_string(test.a)<<"\n";
}
int main()
{
solo test1;
test1.a = 1;
duo test2;
test2.b = 2;
function(test1);
function(test2);
}
Run Code Online (Sandbox Code Playgroud)
回答您关于模板的问题(尽管在此特定应用程序中,由于多种原因,这不是正确的解决方案):
它不像你写的那样工作的原因是模板实例化发生在编译时,唯一发生的事情std::is_same是为模板参数计算的值。因此,在function<solo>该行的代码中
if(std::is_same<T, duo>::value) std::cout<< std::to_string(test.b);
Run Code Online (Sandbox Code Playgroud)
会像
if(false) std::cout<< std::to_string(test.b);
Run Code Online (Sandbox Code Playgroud)
这不编译因为没有成员b在test。
为了使它工作,你需要两个模板,并在实例化模板时使用 SFINAE 选择正确的一个(并且由于函数模板不能部分特化,你需要像下面这样写,这真的是写两个的愚蠢方式重载。或者您可以完全专门化模板,但是您不会使用if_same)。
template<class T>
typename std::enable_if<!std::is_same<T, duo>::value, void>::type function(T test){
std::cout<< std::to_string(test.a);
}
template<class T>
typename std::enable_if<std::is_same<T, duo>::value, void>::type function(T test){
std::cout<< std::to_string(test.a);
std::cout<< std::to_string(test.b);
}
Run Code Online (Sandbox Code Playgroud)
此外,请注意 is_same 查看变量的静态类型,因此如果您有solo&一个duo对象,它仍然会选择solo重载。
模板的一个不那么愚蠢的用法是编写一个函数模板,它可以处理具有成员的任何类型int b。这使用了一个辅助元函数(一个结构体,所以我们可以使用偏特化):
template <class T, class = int>
struct has_member_b : std::false_type {};
template <class T>
struct has_member_b<T, decltype(std::declval<T>().b)> : std::true_type {};
template<class T>
typename std::enable_if<has_member_b<T>::value, void>::type function(T test){
std::cout<< std::to_string(test.a);
std::cout<< std::to_string(test.b);
}
template<class T>
typename std::enable_if<!has_member_b<T>::value, void>::type function(T test) {
std::cout<< std::to_string(test.a);
}
Run Code Online (Sandbox Code Playgroud)
(请注意,两个版本都假定存在成员a,否则将无法编译)
| 归档时间: |
|
| 查看次数: |
3216 次 |
| 最近记录: |