C 模板 - 使用“std::is_same_v”而不是专门化并避免编译错误?

新手上路,请多包涵

我是模板的新手,我正在尝试使用它们以避免重复非常相似的功能。

在下面的示例中,我制作了一个简单而小型的工作示例来显示我的问题。

特别是,我有两个 struct (“solo”和“duo”)。这些结构有一个共同的成员(a),其中一个有一个特定的成员(b)。

然后我有一个模板函数,它可以采用任何一个结构并打印成员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);
}

原文由 Hugo 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
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 ,否则将无法编译)

原文由 drRobertz 发布,翻译遵循 CC BY-SA 4.0 许可协议

你不需要模板,因为 duo extends solo 。只需从 function(duo) 调用 function(solo)

 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);
}

原文由 Holt 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题