繁体   English   中英

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

[英]Template conversion operator priority & constness

我有类似的东西:

#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

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

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

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

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

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

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

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

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

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

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

比较转换序列时,在转换结果类型之前会考虑参数的转换。 隐式对象参数( this指针)被视为参数,限定转换( Foo -> Foo const )比隐式对象参数的标识转换更差。 来自[over.match.best]

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

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

所以非const -qualified成员转换操作符总是比一个更好的const -qualified一个,即使结果转换确切后者。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM