【问题标题】:Why `void` is required while declaring a class template which is to be specialized using `enable_if`为什么在声明要使用 `enable_if` 专门化的类模板时需要 `void`
【发布时间】:2020-07-09 12:51:54
【问题描述】:

我正在学习 C++ 模板元编程,偶然发现了一个与 SFINAE 相关的简单问题(我相信如此)。特别是,我正在编写一个模板类,它将为我们提供最大尺寸的类型。我通过将类型与sizeof 运算符进行比较,将type 别名为正确的类型,具体取决于它们的大小。我正在使用enable_if 选择正确的类专业化。我不明白的是为什么在声明要使用enable_if 专门化的类模板时,需要将void 作为class Enable 的默认值提供。

以下代码可以正常工作

// test.cpp
#include <type_traits>

// void works just fine but if changed to anything else say int, compilation fails!
template < typename L, typename R, class Enable = void > struct MaxTypeT;

template < typename L, typename R >
struct MaxTypeT<L, R, typename std::enable_if< (sizeof(L) >= sizeof(R)) >::type> {
    using type = L;
};

template < typename L, typename R >
struct MaxTypeT<L, R, typename std::enable_if< (sizeof(L) < sizeof(R)) >::type> {
    using type = R;
};

int main(){
    static_assert(std::is_same< MaxTypeT<int, double>::type, double >::value, "MaxTypeT not working");
    return 0;
}

但是当我将class Enable = void 更改为任何其他类型比如class Enable = int 时,我会收到以下错误。为什么这里需要void

test.cpp: In function ‘int main()’:
test.cpp:17:56: error: incomplete type ‘MaxTypeT<int, double>’ used in nested name specifier
     static_assert(std::is_same< MaxTypeT<int, double>::type, double >::value, "MaxTypeT not working");
                                                        ^~~~
test.cpp:17:56: error: incomplete type ‘MaxTypeT<int, double>’ used in nested name specifier
test.cpp:17:69: error: template argument 1 is invalid
     static_assert(std::is_same< MaxTypeT<int, double>::type, double >::value, "MaxTypeT not working");

【问题讨论】:

    标签: c++ c++11 templates template-meta-programming enable-if


    【解决方案1】:

    std::enable_if&lt;&gt;::type 默认为void。因此,在模板替换发生后,您的每个专业都有第三个参数void

    // primary template
    template < typename L, typename R, typename Enable = void > struct MaxTypeT;
    
    // specialization #1
    template < typename L, typename R >
    struct MaxTypeT<L, R, void> {
        using type = L;
    };
    
    // specialization #2
    template < typename L, typename R >
    struct MaxTypeT<L, R, void> {
        using type = R;
    };
    

    当您执行MaxTypeT&lt;int, double&gt; 时,它会实例化类型MaxTypeT&lt;int, double, void&gt;,因为默认参数Enable 设置为void

    如果 Enable 设置为 int,它会实例化类型 MaxTypeT&lt;int, double, int&gt;。由于编译器无法将特化与那些参数类型匹配,因此它与仅声明且未定义的主模板一起使用,因此出现错误。

    正如Öö Tiib 在他的回答中所说,std::enable_if 有第二个模板参数,用于指定其::type 成员将是什么。如果您将其设置为int,那么在模板替换成功后,它将是第三个参数为int 的特化。

    【讨论】:

      【解决方案2】:

      void 不是必需的,它只是为您节省了一些输入。如果你想在那里有int,那么你应该这样写:

      // test.cpp
      #include <type_traits>
      
      // int works just fine now
      template < typename L, typename R, typename Enable = int > struct MaxTypeT;
      
      
      // note additional template argument of enable_if
      template < typename L, typename R >
      struct MaxTypeT<L, R, typename std::enable_if< (sizeof(L) >= sizeof(R)), int >::type> {
          using type = L;
      };
      
      template < typename L, typename R >
      struct MaxTypeT<L, R, typename std::enable_if< (sizeof(L) < sizeof(R)), int >::type> {
          using type = R;
      };
      
      int main(){
          static_assert(std::is_same< MaxTypeT<int, double>::type, double >::value, "MaxTypeT not working");
          return 0;
      }
      

      enable if 的第二个参数默认为void,因此要匹配它,您的模板还必须有void 或为enable_if 提供不同的类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-07
        • 1970-01-01
        • 1970-01-01
        • 2021-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多