Class 模板内的模板专业化 class

Class template specialization within template class

重构遗留代码我想合并彼此相关的单独模板 classes/structs(以避免命名空间污染)。

Nested(下图)是 MyStruct 的帮手 class,我想将其移动 MyStruct

但我做不到:

#include <type_traits>
#include <iostream>

struct YES {} ;
struct NO {};

template <typename TYPE>
struct MyStruct
{

    template <typename TYPE_AGAIN = TYPE, typename SELECTOR = NO>
    struct Nested
    {
        static void Print(void)
        {
            std::cout << "MyStruct::Nested<bool = false>::Print()" << std::endl;
        }
    };


    template <>
    struct Nested<TYPE, typename std::enable_if<std::is_integral<TYPE>::value, YES>::type>
    {
        static void Print(void)
        {
           std::cout << "MyStruct::Nested<bool = true>::Print()" << std::endl;
        }
    }; 

};

编译器抱怨:

g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from ../main.cpp:8:0:
../MyStruct.h:31:12: error: explicit specialization in non-namespace scope ‘struct MyStruct<TYPE>’
  template <>
            ^
make: *** [main.o] Error 1

其实我也很困扰必须包括

<typename TYPE_AGAIN = TYPE>

但是没有,抱怨就更多了:

g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
In file included from ../main.cpp:8:0:
../MyStruct.h:31:12: error: explicit specialization in non-namespace scope ‘struct MyStruct<TYPE>’
  template <>
            ^
../MyStruct.h:32:9: error: template parameters not used in partial specialization:
  struct Nested<typename std::enable_if<std::is_integral<TYPE>::value, YES>::type>
     ^
../MyStruct.h:32:9: error:         ‘TYPE’
make: *** [main.o] Error 1

你不能在非命名空间范围内专门化模板,就像你的例子中的 struct

您必须将特化放在结构定义之外:

template<typename TYPE> template<>
struct MyStruct<TYPE>::Nested<...> {};

但是现在你有另一个问题,如果你想在模板中特化一个模板class,你必须为每个模板特化它class。您不能只专门化一个成员函数,您必须专门化整个 class.

所以,你需要这样做:

template<> template<>
struct MyStruct<int>::Nested<...> {};

此外,您真的不需要 SFINAE:

template<typename SELECTOR>
struct Nested; // Default invalid SELECTOR

template<>
struct Nested<YES> { /*...*/ };

template<>
struct Nested<NO> { /*...*/ };

这里有一种方法可以让它发挥作用:

#include <type_traits>
#include <iostream>

template <typename TYPE>
struct MyStruct
{
  template <typename SEL_TYPE = TYPE>
  static typename std::enable_if<std::is_integral<SEL_TYPE>::value && std::is_same<TYPE, SEL_TYPE>::value, void>::type
  Print(void)
  {
    std::cout << "MyStruct::Nested<is_integral::Print()" << std::endl;
  }

  template <typename SEL_TYPE = TYPE>
  static typename std::enable_if<!std::is_integral<SEL_TYPE>::value && std::is_same<TYPE, SEL_TYPE>::value, void>::type
  Print(void)
  {
    std::cout << "MyStruct::Nested<not is_integral>::Print()" << std::endl;
  }

};

嵌套结构实际上已经过时了——这只是之前单独建模的遗留物。

我想合并的是 Print() 函数。

不过,这里需要std::is_same<>来强制。 否则有人可能会调用

MyStruct<std::string>::Print<int>();

您无法编译代码似乎有两个原因:

  • 完全特化 内部模板 class 不能在 class。最好的解决方案是添加一个愚蠢的默认模板参数,然后 声明内部模板的部分特化 class.

  • 模板特化不能直接std::enable_if禁用。但是我们可以使用 void_t 技巧来做到这一点。 void_t 是 c++17 的特性,所以对于早期的 c++ 标准,我们需要提供它的定义。我从 http://en.cppreference.com/w/cpp/types/void_t.

  • 中获取了 void_t 定义

因此您可以按如下方式重写代码:

 #include <type_traits>
 #include <iostream>
 #include <type_traits>

 //Crédit: cpp-reference.com
 template<typename... Ts> struct make_void { typedef void type;};
 template<typename... Ts> using void_t = typename make_void<Ts...>::type;

 template <typename TYPE>
 struct MyStruct
 {
     //The third parameter is an unused parameter 
     template <typename TYPE_AGAIN = TYPE, typename SELECTOR = void
               , typename = void>
     struct Nested
     {
         static void Print(void)
         {
             std::cout << "MyStruct::Nested<bool = false>::Print()" << std::endl;
         }
     };

     //We declare a partial specialization, T go to the third parameter. We use the void_t trick here.
     template <class T>
     struct Nested<TYPE,
                  void_t<typename std::enable_if<
                                      std::is_integral<TYPE>::value>::type>
                        ,T>
     {
         static void Print(void)
         {
            std::cout << "MyStruct::Nested<bool = true>::Print()" << std::endl;
         }
     }; 

 };

 int main(){
    MyStruct<int>::Nested<>::Print();
    return EXIT_SUCCESS;
 }