我是模板的新手,我试图使用它们以避免重复非常相似的功能。
在下面的例子中,我做了一个简单而小巧的工作示例来说明我的问题。
特别是,我有两个结构(" solo"和#34; duo")。这些结构有一个共同的成员(a),其中一个有一个特定的成员(b)。
然后我有一个模板函数,它可以采用struct并打印成员a ...我希望它只能在结构类型为" 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);
}
答案 0 :(得分:2)
回答关于模板的问题(尽管在这个特定的应用程序中,由于许多原因,它不是正确的解决方案):
它写入时不起作用的原因是模板实例化在编译时发生,然后发生的唯一事情就是为模板参数计算std::is_same
的值。因此,在function<solo>
行的代码中
if(std::is_same<T, duo>::value) std::cout<< std::to_string(test.b);
就像
if(false) std::cout<< std::to_string(test.b);
由于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);
}
此外,请注意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);
}
(请注意,两个版本都假设有一个成员a
,如果没有,它将无法编译)
答案 1 :(得分:1)
自duo
扩展solo
以来,您不需要模板。只需从function(solo)
致电function(duo)
:
void function(solo test) {
std::cout << std::to_string(test.a);
}
void function(duo test) {
function((solo) test);
std::cout << std::to_string(test.b);
}
答案 2 :(得分:0)
随着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);
}