2014-04-07 70 views
1

我更喜歡將類和函數模板的定義寫入單獨的文件中,該文件自動包含在「public」標頭後面。但是,我遇到了一個有趣的案例,看起來我無法做到這一點。內部類模板的非成員操作符重載

template <typename T> 
class Outer 
{ 
public: 
    template <typename U> 
    class Inner 
    { 
     friend bool operator ==(const Inner& lhs, const Inner& rhs); 
    }; 
}; 

using Type = Outer<int>::Inner<short>; 

int main() 
{ 
    Type a; 
    Type b; 
    a == b; 
} 

是否有可能寫的operator==定義分離,將任何TU工作?

回答

1

正如Igor Tandetnik指出的那樣,您的示例聲明瞭一個非模板的朋友函數,您必須爲每個模板實例化重載,這是允許朋友函數內聯定義的一個原因(因此可以生成它們通過模板本身而不必是模板)。

如果要定義友元函數爲模板,這裏是我能夠拿出最接近:

template <typename T> 
struct Outer { 
    template <typename U> 
    struct Inner; 
}; 

template<typename T, typename U> 
bool operator==(typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const &); 

template <typename T> 
template <typename U> 
struct Outer<T>::Inner { 
    friend bool operator==<T,U>(Inner const &, Inner const &); 
}; 

template<typename T, typename U> 
bool operator==(typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const &) { 
    return true; 
} 

// I switched this out, because my gcc-4.6 doesn't 
// understand "using" aliases like this yet: 
typedef Outer<int>::Inner<short> Type; 

int main() { 
    Type a; 
    Type b; 
    operator==<int,short>(a, b); 
} 

不幸的是,你會發現這個操作符函數的調用網站是非常尷尬:operator==<int,short>(a, b)。我相信在這樣的嵌套類模板上定義一個函數模板會禁用(或者至少干擾)參數推導,所以你必須顯式地指定模板參數(這意味着將其作爲一個函數而不是以運算符形式進行調用)。這就是爲什麼內聯朋友定義非常方便。如果你真的想單獨定義你的operator==的代碼,我建議定義內聯的friend以調用另一個函數模板(使用適當的模板參數),然後可以將其作爲一個自由函數進行異步定義。

+0

嗯,這是一個非常好的解釋,我現在將決定使用內聯定義,但會牢記您的建議。 – Lyberta

2

對於一個特定的專業化,是:

template <typename T> 
class Outer 
{ 
public: 
    template <typename U> 
    class Inner 
    { 
     int x = 42; 
     friend bool operator ==(const Inner& lhs, const Inner& rhs); 
    }; 
}; 

using Type = Outer<int>::Inner<short>; 

bool operator ==(const Type& lhs, const Type& rhs) { 
    return lhs.x == rhs.x; 
} 

int main() 
{ 
    Type a; 
    Type b; 
    a == b; 
} 

在您的例子中,模板的每個專業化協助一個非模板函數,接受特定的專業化作爲參數。你可以在類中定義這個函數(然後每次模板被實例化時它都會被打印出來),或者你可以在課堂外定義它 - 但是然後你必須爲每次使用的特化定義一個函數。

+0

「in-class」意思是不在一個單獨的文件中,對嗎? – Lyberta

+1

劃定類定義主體的大括號內的類內含義。我想你原則上可以把它移動到一個單獨的文件中,如果你足夠絕望,可以在類定義中包含它。 –