【问题标题】:Why compile error with enable_if为什么用 enable_if 编译错误
【发布时间】:2012-12-07 12:24:48
【问题描述】:

为什么这不能用 gcc48 和 clang32 编译?

#include <type_traits>

template <int N> 
struct S {

    template<class T> 
    typename std::enable_if<N==1, int>::type
    f(T t) {return 1;};

    template<class T> 
    typename std::enable_if<N!=1, int>::type
    f(T t) {return 2;};
};

int main() {
    S<1> s1;
    return s1.f(99);
}

GCC 错误:

/home/lvv/p/sto/test/t.cc:12:2: error: no type named ‘type’ in ‘struct enable_if<false, int>’
  f(T t) {return 2;};
  ^

CLANG 错误:

/home/lvv/p/sto/test/t.cc:11:26: error: no type named 'type' in 'std::enable_if<false, int>'; 'enable_if' cannot be used to
      disable this declaration
        typename std::enable_if<N!=1, int>::type
                                ^~~~
/home/lvv/p/sto/test/t.cc:16:7: note: in instantiation of template class 'S<1>' requested here
        S<1> s1;
             ^

编辑 - 解决方案

我已接受 Charles Salvia 的回答,但出于实际原因,我无法使用建议的解决方法(专门研究 N)。我找到了其他适合我的解决方法。使enable_if 依赖于T:

typename std::enable_if<(sizeof(T),N==1), int>::type

【问题讨论】:

  • 您确定这仍然可以工作吗?您不能仅通过方法的返回类型来重载方法(除非 enable_if 是作为一种语言结构实现的,而不是像我目前假设的那样通过一个简单的模板类实现)。
  • 为什么使 enable_if 依赖于 T 的解决方法是必要的,究竟是什么?
  • 该解决方案对我不起作用!我得到了error: no matching function for call ...
  • @LiDong - 我的解决方案?这就是你否决这个问题的原因?我在这里问一个问题。答案请看下面。
  • @LeonidVolnitsky sizeof(T) 在我的情况下不起作用。很抱歉投反对票。那时我只是沮丧。我在 C++11 中使用了默认模板参数。

标签: c++ templates metaprogramming sfinae enable-if


【解决方案1】:

因为您在函数模板中使用enable_if 而不使用模板参数T。如果要在结构体S 具有特定模板参数值N 时进行特化,则需要使用类模板特化。

template <int N, class Enable = void> 
struct S {  };

template <int N>
struct S<N, typename std::enable_if<N == 1>::type>
{
  ....
};

【讨论】:

    【解决方案2】:

    好吧,我不确定你想做什么,但也许这段代码会有所帮助:

    #include <iostream>
    
    template <int N>
    struct S {
    
        template<class T=int>
        typename std::enable_if<N==1, T>::type
        f(T t) {return 1;}
    
        template<class T=int>
        typename std::enable_if<N!=1, T>::type
        f(T t) {return 2;}
    };
    
    int main()
    {
        S<1> s1;
        S<2> s2;
        std::cout << s1.f(99) << " " << std::endl << s2.f(5);
    }
    

    这会打印 1 和 2。

    【讨论】:

      【解决方案3】:

      要让std::enable_if 像这样工作,您依赖于 SFINAE。不幸的是,在你声明的时候

      S<1> s1;
      

      它将实例化所有S&lt;1&gt; 的成员声明。只有当S&lt;1&gt; 是一个格式错误的构造时,SFINAE 才会在此时发挥作用。它不是。不幸的是,它包含一个无效的函数,因此S&lt;&gt; 的实例化是无效的。

      对于这样的事情,我可能会使用单独的模板结构:

      template <bool B>
      struct f_functor {
          template <typename T>
          static int f(T t) { return 1; }
      };
      
      template <>
      struct f_functor<false> {
          template <typename T>
          static int f(T t) { return 2; }
      };
      
      template <int N> 
      struct S {
      
          template<class T> 
          typename int f(T t) { return f_functor<N==1>::f(t); }
      };
      

      【讨论】:

      【解决方案4】:

      使用默认的布尔模板参数,如下所示:

      template <int N> 
      struct S {
      
          template<class T, bool EnableBool=true> 
          typename std::enable_if<N==1 && EnableBool, int>::type
          f(T t) {return 1;};
      
          template<class T, bool EnableBool=true> 
          typename std::enable_if<N!=1 && EnableBool, int>::type
          f(T t) {return 2;};
      };
      

      【讨论】:

        【解决方案5】:

        对于这种情况,您可以考虑完全不使用 enable_if。可以简单地专门化 f:

        template <int N> 
        struct S {
            template<class T> int f(T t);
        };
        
        template<int N>
        template<class T>
        int S<N>::f(T t) { return 2; }
        
        template<>
        template<class T>
        int S<1>::f(T t) { return 1; }
        
        int main() {
            S<1> s1;
            return s1.f(99);
        }
        

        【讨论】:

          猜你喜欢
          • 2018-04-08
          • 1970-01-01
          • 2015-10-17
          • 1970-01-01
          • 2012-02-08
          • 1970-01-01
          • 1970-01-01
          • 2014-06-08
          • 1970-01-01
          相关资源
          最近更新 更多