2016-10-16 97 views
4

重構遺留代碼我想合併彼此相關的單獨模板類/結構(以避免命名空間污染)。模板類中的類模板特殊化

Nested(下圖)爲MyStruct一個輔助類,這是我想要移動到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 

回答

5

非命名空間範圍不能專門的模板,像你的情況一個struct

你將不得不把專業化的結構定義之外:

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

但現在你有另外一個問題,如果你想專注模板類的內部模板,你必須專門針對每個模板類別。你不能專門化一個成員函數,你必須專門化整個類。

所以,你需要這樣做:

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

此外,你真的不需要SFINAE此:

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

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

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

非常感謝! - 這個模板<>模板<>語法對我來說是新的。 –

+0

好吧,似乎我太快把這作爲解決我的問題。 –

+0

我仍然在圈子中跑步。完全專門化外部類MyClass是不好的。我想利用由MyClass的模板參數驅動的內部類嵌套。看起來,這是不可能的?或者它只是「糟糕的設計」 - 我們必須爲此使用外部策略類並且不能將其嵌入到MyClass中? –

0

這裏有一個方法,使其工作:

#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; 
    } 

}; 

結構嵌套實際上是obsolet - 這只是從之前單獨建模的剩餘物。

這是我想要包含的Print()函數。

但是,std :: is_same <>在這裏需要強制< SEL_TYPE = TYPE>。 否則有人會調用

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

有沒有辦法將這個工作選項變成一個語法較少的糖 - 使用SEL_TYPE = TYPE? –

1

似乎有2個原因,你不能編譯代碼:

  • 一個全特殊化內模板類的不能被內部聲明班上。最好的解決方案是添加一個默認的啞模板參數,然後聲明內部模板類的部分專用

  • 模板專業化不能直接被禁用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; 
}