2015-12-20 81 views
4

我想在模板類內的模板類的外部類模板運算符寫入。模板類中的模板類的外部類運算符

我希望以下代碼片段能解釋我的意思。

enum MyEnum {}; 

template <MyEnum a> 
class ClassWithTemplateClass { 
public: 
    template <bool B> 
    class TemplateClass { 
     // ... 
    }; 
}; 

當我寫操作是這樣的:

template <MyEnum enumVal, bool B> 
auto operator<<(ClassWithTemplateClass<enumVal>::TemplateClass<B> &a, int b) { 
    // ... 
    return a; 
} 

編譯器返回的錯誤:

錯誤:的 '運營商< <' 非函數聲明

你能告訴我我該如何寫這個操作符?

+0

嘗試用你的錯誤信息搜索:HTTP:// STAC koverflow.com/search?q=error%3A+declaration+of+%27operator%3C%3C%27+as+non-function。有不少問題(和答案)。 –

+1

你真的不能在類模板定義之外寫這個。使用'typename'和'template'可以編譯它們,但是整個事情是一個非推導的上下文,所以除非明確地做 - 否則操作符將永遠不會被調用 - 這會破壞整個操作符的重載點。 –

回答

1

ClassWithTemplateClass<enumVal>::nested name specifier,它又是non-deduced context。由於enumVal是一個模板參數,它顯示在範圍解析運算符::的左側,編譯器無法推斷其值。

<<操作者可以定義(1)作爲內部TemplateClass類的朋友:

enum MyEnum { X, Y, Z }; 

template <MyEnum E> 
struct ClassWithTemplateClass 
{ 
    template <bool B> 
    struct TemplateClass 
    { 
     friend auto& operator<<(TemplateClass& a, int b) 
     { 
      return a; 
     } 
    }; 
}; 

其中TemplateClass總是指的ClassWithTemplateClass<?>::TemplateClass<?>

DEMO

或特定實例(2) inside ClassWithTemplateClass

enum MyEnum { X, Y, Z }; 

template <MyEnum E> 
struct ClassWithTemplateClass 
{ 
    template <bool B> 
    struct TemplateClass 
    { 
    }; 

    template <bool B> 
    friend auto& operator<<(TemplateClass<B>& a, int b) 
    { 
     return a; 
    } 
}; 

DEMO 2

或,(3),你可以提供爲每個預定義的枚舉值的單獨的操作符定義(儘管它可以具有比定義爲常數更多的值),使得要推導出僅B需求:

enum MyEnum { X, Y, Z }; 

template <MyEnum E> 
struct ClassWithTemplateClass 
{ 
    template <bool B> 
    struct TemplateClass 
    {   
    }; 
}; 

template <bool B> 
auto& operator<<(ClassWithTemplateClass<X>::TemplateClass<B>& a, int b) 
{ 
    return a; 
} 

template <bool B> 
auto& operator<<(ClassWithTemplateClass<Y>::TemplateClass<B>& a, int b) 
{ 
    return a; 
} 

template <bool B> 
auto& operator<<(ClassWithTemplateClass<Z>::TemplateClass<B>& a, int b) 
{ 
    return a; 
} 

DEMO 3

,或者(4)店模板參數爲TemplateClass靜態數據成員,並用它們既能使運營商SFINAE,能夠和檢索其價值S:

enum MyEnum { X, Y, Z }; 

template <MyEnum E> 
struct ClassWithTemplateClass 
{ 
    template <bool B> 
    struct TemplateClass 
    { 
     static constexpr MyEnum ClassWithTemplateClass_E = E; 
     static constexpr bool TemplateClass_B = B; 
    }; 
}; 

template <typename T 
     , MyEnum E = T::ClassWithTemplateClass_E 
     , bool B = T::TemplateClass_B> 
auto& operator<<(T& a, int b) 
{ 
    return a; 
} 

DEMO 4

作爲另一種選擇,(5),你可以派遣從operator<<調用另一個函數,並明確指定模板參數,使該簽名是完全按照你想要的,模板參數已知:

enum MyEnum { X, Y, Z }; 

template <MyEnum E> 
struct ClassWithTemplateClass; 

template <MyEnum E, bool B> 
auto& print(typename ClassWithTemplateClass<E>::template TemplateClass<B>& a, int b); 

template <MyEnum E> 
struct ClassWithTemplateClass 
{ 
    template <bool B> 
    struct TemplateClass 
    { 
     friend auto& operator<<(TemplateClass& a, int b) 
     { 
      return print<E, B>(a, b); 
     } 
    }; 
}; 

template <MyEnum E, bool B> 
auto& print(typename ClassWithTemplateClass<E>::template TemplateClass<B>& a, int b) 
{ 
    return a; 
} 

DEMO 5

+0

謝謝你的回答。由於運營商<<將由我的圖書館的最終用戶定義,唯一可行的解​​決方案就是您的最後一個演示。但是對於我的圖書館用戶來說,這個解決方案可能太令人困惑,所以我認爲,我需要重新設計圖書館的這一部分。 – pokas

+0

@pokas如何[這個解決方案](http://coliru.stacked-crooked.com/a/4902a6156f460378),最終用戶應該提供函數'print_template_class'? –