【问题标题】:enable_if cannot be used to disable this declarationenable_if 不能用于禁用此声明
【发布时间】:2015-05-21 17:41:36
【问题描述】:

我显然没有足够的 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

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

能否请你迂腐解释一下我在这里做错了什么?

【问题讨论】:

  • enable_if 通常不用于禁用类类型。你想在这里完成什么? more_than_99&lt;500&gt; 似乎工作正常。
  • 我需要在尝试实例化类似 `more_than_99 x;' 的东西时抛出一个错误在我尝试实例化它的那一行。类似于“嘿,这种类型不存在”。
  • @MatteoMonti 这就是它的意思。由于bool 为假,因此没有定义T
  • 但是……难道没有办法在声明的那一行说吗?
  • 错误消息指向声明(对于上下文)和实例化(对于 this 类型无效,它可能对其他类型有效)。但我很确定错误消息取决于编译器。

标签: c++ templates sfinae


【解决方案1】:

关于为什么错误发生在模板定义而不是实例化的其他答案是正确的。

在尝试实例化类似 `more_than_99 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&lt;0,true&gt;,这也适用 (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&lt;0,true&gt; 的恶意实例化。

【讨论】:

  • 这正是我想要的! :)
  • 如果你 more_than_99&lt;0, true&gt; 就不会。不是很扎实。
  • @black 即使在原始示例中,more_than_99&lt;0,void&gt; 也会绕过enable_if。我不确定是否可以防止恶意实例化。
【解决方案2】:

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
}

【讨论】:

  • 谢谢,这解释了 std::enable_if 背后的概念(就 SFINA 而言)。
【解决方案3】:

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

一个非类型模板参数是依赖的,如果它的类型是依赖的,或者它指定的常量表达式是值依赖的。

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

【讨论】:

    【解决方案4】:

    使用静态断言:

    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;
    

    【讨论】:

      【解决方案5】:

      来自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
      

      【讨论】:

        猜你喜欢
        • 2021-02-18
        • 1970-01-01
        • 1970-01-01
        • 2018-11-15
        • 1970-01-01
        • 1970-01-01
        • 2022-12-18
        • 2016-03-13
        • 2020-11-15
        相关资源
        最近更新 更多