使用std::is_same的元编程

13

是否可能做到以下这样的事情,而不需要进行模板特化,从而编译通过?

template <class T> 
class A {
public:
    #if std::is_same<T, int>
        void has_int() { }
    #elif std::is_same<T, char>
        void has_char() { }
    #endif
};
A<int> a; a.has_int();
A<char> b; b.has_char();

3
不能将预处理器语句与C++编译器的模板实例化混合使用。 - πάντα ῥεῖ
2
你是指 A<char> b,对吗? - qdii
2个回答

24
是的。编写函数模板,然后使用 std::enable_if 条件性启用它们:
#include <type_traits>

template <class T> 
class A {
public:

  template<typename U = T>
  typename std::enable_if<std::is_same<U,int>::value>::type
  has_int() {}

  template<typename U = T>
  typename std::enable_if<std::is_same<U,char>::value>::type
  has_char() {}
};

int main()
{
    A<int> a;
    a.has_int();   // OK
    // a.has_char();  // error
}

如果类很大并且有许多需要无论 T 是什么都需要的函数,则来自另一个答案的解决方案可能不可行。但是,您可以通过继承仅用于这些特殊方法的另一个类来解决此问题。然后,您只能专门化该基类。

在C ++ 14中,有方便的类型别名,因此语法可以变为:

std::enable_if_t<std::is_same<U, int>::value>

而C++17更短:

std::enable_if_t<std::is_same_v<U, int>>

太棒了!非常感谢。 - ZeroCool
3
你可以补充说明,在C++14中,你可以编写std::enable_if_t,而在C++17中,甚至可以使用std::is_same_v来消除typename ... ::type::value的冗长性。请保持原文意思不变,但要让翻译更加易懂通俗。 - TemplateRex

6
是的,可以通过模板特化实现:
template <class T> 
class A;

template <> 
class A<int>
{
    void had_int(){}
};

template <> 
class A<char>
{
    void had_char(){}
};

1
@ZeroCool 或许在未来你可以看一下这个链接:http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Static-If-I-Had-a-Hammer - 5gon12eder
@BЈовић 但是可以假设那些类有更多的成员是相同的。 - Sebastian Redl
2
@5gon12eder 静态 if 在委员会中被否决了。目前还没有听说有任何努力将其重新引入。 - Sebastian Redl
@BЈовић 感谢您的建议。实际上,原始类非常庞大,我同意这不是一个好的设计。将其拆分并进行模板专业化将会创建比已经需要的代码更多的代码。 - ZeroCool
@SebastianRedl 我不知道这件事。我了解的情况是它被推迟到以后再做决定。说实话,我对这个决定并不太难过,我必须承认... - 5gon12eder
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接