【问题标题】:Template conversion operator priority & constness模板转换运算符优先级和常量
【发布时间】:2015-05-06 21:48:47
【问题描述】:

我有一些类似的东西:

#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 点让我认为我应该进行身份转换,转换为布尔值,使用带有T = bool 的模板转换运算符实例化,尽管显然有一个微妙的隐藏某处。有人能告诉我这里有什么规则吗?

【问题讨论】:

  • 运算符 Foo* 的优先级高于模板运算符,并且 Foo* 可以隐式转换为 bool,因此编译器选择 Foo* 重载而不是模板。
  • 创建身份转换的潜在实例化不应该具有更高的优先级吗?似乎常量性主要是选择正确转换的原因
  • 如果是模板化,显然不会
  • @Creris 不正确。

标签: c++ templates overload-resolution


【解决方案1】:

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

鉴于这些定义,一个可行函数F1 被定义为比另一个可行函数更好的函数 F2 如果对于所有参数 i,ICSi(F1) 并不比 ICSi(F2 ),然后
(1.3) — 对于某些论点 j,ICSj(F1) 是比 ICSj(F2) 更好的转换序列,或者,如果不是,
(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(身份 - 最高等级)的转换序列是更好的转换序列比从 Foo*bool (布尔转换 - 最低)。

【讨论】:

  • 非常感谢您的解释!
【解决方案2】:

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

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

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

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

【讨论】:

  • 好吧,那是有道理的!非常感谢您为标准配音以使其更具可读性:)
猜你喜欢
  • 2021-01-01
  • 2018-04-07
  • 2016-02-19
  • 2017-07-04
  • 2019-05-15
  • 2012-05-04
  • 2011-06-21
  • 2020-03-05
  • 1970-01-01
相关资源
最近更新 更多