2014-04-03 14 views
0

我想了解我觀察到的C++語言行爲(我理解了它的前半部分)。模板扣除:爲什麼它與繼承一起工作(當它轉換失敗時)?

我的設置:2個模板類:ACA可以轉換爲C,但不是相反。他們有一些共同的行爲,所以我正在尋找實現一些邏輯只與C,並依靠從AC轉換,使A行爲方式與C相同。
該示例使用運算符重載,但我認爲與功能或方法相同的討論。

我第一次嘗試是使用一個轉換構造函數:

template <class T> 
class A { 
}; 

template <class T> 
class C { 
    public: 
    C() = default; 
    C(const A<T>&) {}; 
}; 

template <class T> 
bool operator<(const C<T> &, const C<T> &) {return true;} 

int main() { 
    A<int> a1, a2; 
    C<int> c1, c2; 

    c1 = a1; // OK, no-brainer 

    c1 < c2; // OK, no-brainer 
    c1 < a1; // template deduction failure 
    a1 < c1; // template deduction failure 
    a1 < a2; // template deduction failure 
} 

其實,這是我認爲我SO和網搜索後明白了上半場。從我收集的模板參數必須完全匹配才能嘗試轉換,並且在這種情況下,如果不考慮可能的轉換,則無法推導出此類轉換,因此不可能進行演繹。如果運營商在C(但我不喜歡它)製作非模板朋友,這可以規避。

我想接下來的事情就是使用繼承:

template <class T> 
class C { 
}; 

template <class T> 
class A : public C<T> { 
}; 

template <class T> 
bool operator<(const C<T> &, const C<T> &) {return true;} 

int main() { 
    A<int> a1, a2; 
    C<int> c1, c2; 

    c1 = a1; // Ok, slicing 

    c1 < c2; // Ok, no-brainer 
    c1 < a1; // Ok, but why? 
    a1 < c1; // Ok, but why? 
    a1 < a2; // Ok, but why? 
} 

對於這個我沒有在網絡上找到的解釋(也許我不知道如何搜索)。

我的問題是,爲什麼可以在模板中推導出當A可轉換爲C因爲是基類C(第二種情況),但是當A只是轉換爲C(第一種情況)不能推斷?


編輯

正如我已經試過了意見建議的KerrekSB:

template <class T> 
bool operator<(const C<T> &, const typename std::common_type<C<T>>::type &) {return true;} 

與我的第一種情況下(轉換,而不是繼承)

在這種情況下:

c1 < c2; // OK 
c1 < a1; // OK, a1 is converted 
a1 < c1; // template deduction failure 
a1 < a2; // template deduction failure 

使用他的答案我認爲c1 < a1的作品,因爲第二個參數不是扣除過程的一部分,所以隱式轉換被認爲是第二個參數。

我也試過:

template <class T> 
bool operator<(const typename std::common_type<C<T>>::type &, const typename std::common_type<C<T>>::type &) {return true;} 

這甚至不能c1 < c2工作。我認爲這是因爲現在扣除過程中沒有涉及參數。

我對不對?

+0

請同時嘗試'template bool operator <(const C&,const typename std :: common_type > :: type&);'。 –

+0

@KerrekSB謝謝你,我也嘗試過。我有兩個結論嗎? (見編輯) – bolov

+1

是的。在未推導的上下文中,隱式轉換變爲可用。有了兩個非推斷的上下文,就沒有什麼可推斷的了。 –

回答

4

我認爲你的情況是由C++ 11,14.8.2.1/4 [temp.deduct。調用]:

一般而言,扣進程試圖找到模板的參數值,這將使推導的(類型A如上所述被變換之後)A相同A。不過,有三種情況,允許一個區別:

- ...

- 如果P是一類和P的形式簡單模板id,然後轉化A可以派生推導出的類A。同樣,如果P是指向simple-template-id類別的指針,轉換的A可以是指向由推導的A指向的派生類的指針。

[注:在14.8.1規定,隱式轉換將在函數參數進行將其轉換爲相應的函數參數的類型,如果該參數包含參與模板參數推導沒有模板參數。除了上述列表中描述的轉換之外,這種轉換也是允許的。 - 注完]

所列出的條款說,派生類型都OK(注意C<T>簡單模板id,由14.2/1),和記解釋說,隱式轉換僅考慮其本身不屬於扣除過程的類型。

相關問題