2015-05-06 69 views
13

我沿着線的東西:模板轉換操作符的優先級和常量性

#include <iostream> 

class Foo; 

struct Test 
{ 
    template <typename T> 
    operator T() const // <----- This const is what puzzles me 
    { 
     std::cout << "Template conversion" << std::endl; 
     return T{}; 
    } 

    operator Foo*() 
    { 
     std::cout << "Pointer conversion" << std::endl; 
     return nullptr; 
    } 
}; 

int main() 
{ 
    Test t; 

    if (t) 
    { 
     std::cout << "ahoy" << std::endl; 
    } 
    bool b = (bool)t; 
    Foo* f = (Foo*)t; 
} 

它建立正常,但是當我運行它,而我希望得到

$> ./a.out 
Template conversion 
Template conversion 
Pointer conversion 

我反而得到

$> ./a.out 
Pointer conversion 
Pointer conversion 
Pointer conversion 

如果我刪除了常量,或使測試實例常量,則一切正常。 更準確地說,當兩個操作符具有相同的常量限定時,重載選擇似乎是有意義的。

13.3.3.1.2點的標準讓我覺得我應該得到一個身份轉換,轉換成一個布爾值,使用模板變換操作實例化一個T = bool,但顯然是有一個精妙藏在什麼地方。有人能告訴我這裏有什麼規則?

+0

運算符Foo *具有比模板運算符更高的優先級,並且Foo *可以隱式轉換爲bool,所以編譯器會選擇Foo *重載而不是模板。 – Creris

+0

創建身份轉換的潛在實例是否應該具有更高的優先級? 似乎常量大多是什麼使得選擇正確的轉換 – chouquette

+0

顯然不是如果它是模板 – Creris

回答

3

比較轉換序列時,在轉換結果類型之前考慮參數的轉換。隱式對象參數(this指針)被視爲參數,並且限定轉換(Foo -> Foo const)比隱式對象參數上的標識轉換更差。從[over.match.best]

1 - [...]可行功能F1是德網絡定義比另一個可行的功能 F2更好的功能,如果對所有的論點我,ICSI(F1 )不是比ICSi(F2)更差的轉換序列,然後對於某些參數j,ICSj(F1)是比ICSj(F2)更好的轉換序列,或者,如果不是,[... ]

所以非const合格的成員轉換運營商將永遠比一個const - 限定一個,即使結果轉換對後者確切無誤。

+0

好吧,那是有道理的! 非常感謝配音標準,使其更具可讀性:) – chouquette

6

相關規則在[over.match.best]定義:

根據這些定義,一個可行的功能F1被定義爲比另一種可行的功能更好的功能 F2如果所有參數,ICS F1)不大於ICS F2)更差的轉換序列,然後
(1.3) - 對一些參數Ĵ,ICS ĴF1)比ICS ĴF2)更好的轉換序列,或者,如果不是,
(1.4) - 上下文是由用戶定義的轉換的初始化(見8.5,13.3 .1.5和13.3.1.6)以及從返回類型F1到目標類型(即,正在初始化的 實體的類型)的標準轉換序列是比返回類型的標準轉換序列更好的轉換序列F2到目標類型。

讓我們看看第一個bool的情況。我們有兩個可行的候選人:

Test::operator T<bool>() const; 
Test::operator Foo*(); 

都稱之爲具有非constTest。對於第二次重載,不需要轉換 - 轉換序列就是簡單的精確匹配。但是,對於第一次過載,隱含的this參數需要經過從Testconst Test的限定轉換。因此,第二次重載是首選 - 我們沒有進入討論返回類型的第二步。

但是如果我們放棄了const,在可行的人選成爲:

Test::operator T<bool>(); 
Test::operator Foo*(); 

在這裏,兩位候選人都具有相同的轉換序列同樣可行的,但由於從返回類型bool轉換序列的bool模板首選到bool(身份 - 最高等級)是一個比從Foo*bool(布爾轉換 - 最低)更好的轉換序列。

+0

非常感謝解釋! – chouquette