为什么这个std :: enable_if不起作用

时间:2016-11-08 20:59:57

标签: c++ c++11 templates sfinae typetraits

从这个问题Why should I avoid std::enable_if in function signatures看来,我应该能够写出

#include <type_traits>
#include <iostream>

enum Class {
    Primary,
    Secondary
};

template<Class C>
class Entity {
public:
    template<typename Cls = C, typename Sec = Secondary, std::enable_if<std::is_same<Cls, Sec>::value>::type = 0>
    void onlyLegalForSecondaryEntities() {
        std::cout << "Works" << std::endl;  
    }
};

int main() {
    Entity<Secondary> e;
    e.onlyLegalForSecondaryEntities();
    return 0;
}

但是这导致编译错误prog.cpp:13:7: note: template argument deduction/substitution failed

如何编译此代码?

1 个答案:

答案 0 :(得分:3)

您对Class使用enum是一个可怕的想法。不要将具有大写差异的语言关键字用作类型名称。

CClass类型的编译时值。它不是一种类型。

typename Cls = C尝试将类型Class的值分配给某个类型。这是一个类似于说“拾起悲伤”的错误。伤心不是名词,它不是你能接受的东西。

使代码编译的最简单方法是完全删除onlyLegalForSecondaryEntities,并删除所有引用。

通常,在标准下,您不能拥有模板方法,该方法仅在某些参数传递给它所在的模板类时才有效。这样做会使您的程序生成错误,无需诊断。

这很接近:

template<Class Cls = C,
  std::enable_if_t< Cls == Secondary, int> =0
>
void onlyLegalForSecondaryEntities() {
    std::cout << "Works" << std::endl;  
}

除了即使在Entity<Primary>上,您也可以.onlyLegalForSecondaryEntities<Secondary>()

如果您不想允许这样做,我会使用CRTP。

template<bool b, class D>
struct empty_if_false {};

template<class D>
struct empty_if_false<true, D> {
  D* self() { return static_cast<D*>(this); }
  D const* self() const { return static_cast<D*>(this); }
  void onlyLegalForSecondaryEntities() {
    // use self() instead of this in this method to get at a this pointer
    std::cout << "Works" << std::endl;  
  }
};

然后:

template<Class C>
class Entity:public empty_if_false< C==Secondary, Entity<C> > {

有条件地拥有该方法。