2015-05-06 47 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