enable_if不能用于禁用此声明

时间:2015-05-21 17:41:37

标签: c++ templates sfinae

我显然没有足够的SFINAE经验来处理这个问题。实际上我的印象是它一直工作到现在,这种问题开始出现在过去的半小时内,在我的代码中无处不在。

#include <iostream>

using namespace std;

template <unsigned int N, typename = typename enable_if <N >= 100> :: type> 
struct more_than_99
{
};

int main()
{
    more_than_99 <0> c;
}

它说

No type named 'type' in 'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable this declaration

在与模板声明对应的行上。到底是怎么回事?我一直使用这种语法来启用和禁用我的模板类,它总是在实例化的行上抛出错误,而不是在声明的行上。

请你迂腐地解释我在这里做错了什么?

5 个答案:

答案 0 :(得分:2)

其他答案对于错误发生在模板定义而不是实例化的原因是正确的。

  

在尝试实例化诸如`more_than_99&lt; 0&gt;之类的内容时,我需要抛出一个错误。 X;'在我试图实例化它的行上。像“嘿,这种类型不存在”之类的东西。

这样的事情怎么样?

template <unsigned int N, bool B = (N>=100)>
struct more_than_99;

template <unsigned int N>
struct more_than_99<N,true>
{};

int main()
{
    more_than_99 <0> c; // error: implicit instantiation of undefined template 'more_than_99<0, false>'
}

为了使它更健壮,并试图防止意外实例化more_than_99<0,true>,这也有效(C ++ 11):

template <unsigned int N, bool B>
struct _impl_more_than_99;

template <unsigned int N>
struct _impl_more_than_99<N,true>
{};

template <unsigned int N>
using more_than_99 = _impl_more_than_99<N, (N>=100)>;

int main()
{
    more_than_99 <0> c; // error: implicit instantiation of undefined template '_impl_more_than_99<0, false>'
}

虽然错误消息引用了_impl_类型。

您可以隐藏详细名称空间中的_impl_或其他内容,只记录more_than_99别名,就好像它是实际类型一样。

但是,您将无法阻止_impl_more_than_99<0,true>的恶意实例化。

答案 1 :(得分:2)

使用静态断言:

template<unsigned int N>
struct more_than_99
{
  static_assert(N >= 100, "N must be more than 99");
};

 more_than_99<1> m1;

导致编译错误,类似于:

testM99.cpp:6:3: error: static_assert failed "N must be more than 99"
  static_assert(N >= 100, "N must be more than 99");
  ^             ~~~~~~~~
testM99.cpp:12:19: note: in instantiation of template class 'more_than_99<1>' 
requested here
  more_than_99<1> m1;

答案 2 :(得分:1)

N不是依赖的非类型模板参数; [temp.dep.temp] / P2

  

非类型模板参数依赖于其类型是依赖的还是它指定的常量表达式依赖于值。

因此,不是发生替换失败,而是直接从格式错误的代码发出错误。

答案 3 :(得分:0)

来自http://en.cppreference.com/w/cpp/types/enable_if :(强调我的)

  

这个元函数是一种方便的方法,可以利用SFINAE 根据类型特征有条件地从重载决策中删除函数,并为不同类型特征提供单独的函数重载和特化std::enable_if可以用作附加函数参数(不适用于运算符重载),返回类型(不适用于构造函数和析构函数),或者作为类模板或函数模板参数。

您无法使用它来启用或停用classstruct

也许您正在寻找类似的东西:

namespace detail
{
   struct more_than_99 {};

   template <bool> Helper;

   template <> Helper<true>
   {
      using type = more_than_99;
   };
}

template <unsigned int N> struct selector
{
   using type = typename detail::Helper<N >= 100>::type
};

using type = selector<10>::type; // Error.

using type = selector<100>::type; // OK.
                                  // type == detail::more_than_99

答案 4 :(得分:0)

如果你有一个类特化(或函数重载),

enable_if是有意义的。它用于在一个实现和另一个实现之间选择,具体取决于模板参数,如果不满足条件则不会触发错误。

这个想法是“如果符合条件,则启用此专业化,否则回退到非专业版本。”

在你的情况下,你可能想要这样的东西:

#include <iostream>
#include <type_traits>

using namespace std;

template<unsigned int N, typename = void >
struct more_than_99
{
    // Implementation if N <= 99
    enum { value = false };
};

template <unsigned int N> 
struct more_than_99<N, typename enable_if <N >= 100> :: type>
{
    // Implementation if N >= 100
    enum { value = true };
};

int main()
{
    cout << more_than_99 <0>::value << endl; //false
    cout << more_than_99 <100>::value << endl; //true
}