模板转换运算符优先级和常量

cho*_*tte 13 c++ templates overload-resolution

我有类似的东西:

#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;
}
Run Code Online (Sandbox Code Playgroud)

它构建良好,但当我运行它,而我期望得到

$> ./a.out
Template conversion
Template conversion
Pointer conversion
Run Code Online (Sandbox Code Playgroud)

我反而得到了

$> ./a.out
Pointer conversion
Pointer conversion
Pointer conversion
Run Code Online (Sandbox Code Playgroud)

如果我删除const,或使Test实例为const,那么一切都按预期工作.更确切地说,当两个运算符具有相同的const限定时,过载选择似乎是有意义的.

13.3.3.1.2标准的要点让我觉得我应该得到一个身份转换,转换为bool,使用带有T= 的模板转换运算符实例化bool,虽然显然有一个隐藏在某处的微妙.有人可以告诉我这里有什么规则发挥作用吗?

Bar*_*rry 6

相关规则在[over.match.best]中定义:

给定这些定义,如果对于所有参数i,可行函数F1被定义为比另一个可行函数更好的函数 ,ICS i()不是比ICS i()更差的转换序列,然后是 (1.3) - 对于某些参数j,ICS j()是比ICS j()更好的转换序列,或者,如果不是, (1.4) - 上下文是用户定义的转换初始化(见8.5,13.3.1.5和13.3.1.6)和从返回类型到目标类型的标准转换序列(即,正在初始化的实体的类型)是比从返回类型到目标类型的标准转换序列更好的转换序列.F2F1F2
F1F2
F1F2

我们来看看第一个bool案例.我们有两个可行的候选人:

Test::operator T<bool>() const;
Test::operator Foo*();
Run Code Online (Sandbox Code Playgroud)

两者都用非调用const Test.对于第二次重载,不需要转换 - 转换序列只是完全匹配.但是,对于第一个重载,隐式this参数需要经历从Test到的限定转换const Test.因此,第二个重载是首选 - 我们没有进入讨论返回类型的第二步.

如果我们放弃了const,那么可行的候选人将成为:

Test::operator T<bool>();
Test::operator Foo*();
Run Code Online (Sandbox Code Playgroud)

在这里,这两个候选者是具有相同转换序列同样可行,但bool由于从返回类型转换序列模板优选bool以bool(认同-最高等级)比从更好的转换序列Foo*,以bool(布尔转换-最低).


eca*_*mur 3

比较转换序列时,会先考虑参数的转换,然后再考虑结果类型的转换。隐式对象参数(this指针)被视为参数,并且限定转换(Foo -> Foo const)比隐式对象参数上的恒等转换差。来自[over.match.best]:

\n\n
\n

1 - [...] 可行函数 F1 被定义为比另一个可行函数更好的函数\n F2 如果对于所有参数 i,ICSi(F1) 不是比 ICSi( 更差的转换序列F2),然后

\n\n

\xe2\x80\x94 对于某些参数 j,ICSj(F1) 是比 ICSj(F2) 更好的转换序列,或者,如果不是这样,[...]

\n
\n\n

因此,非const限定成员转换运算符总是比const限定的成员转换运算符更好,即使后者的转换结果是精确的。

\n