【问题标题】:static_cast : Conversion function templates - are they really working?static_cast :转换函数模板——它们真的有效吗?
【发布时间】:2020-02-19 02:18:24
【问题描述】:

据我阅读static_cast,以下代码应该可以工作:

#include <iostream>
#include <string>

class ConvSample
{
public:
    template<typename T>
    constexpr operator T(){
        return {};
    }
};

int main()
{
    ConvSample aInst;

    int i = aInst;
    std::cout << i << "\n";

    std::string str = static_cast<std::string>(aInst);
    std::cout << str << "\n";

    return 0;
}

它可以完美地与 Clang 等一些编译器配合使用。但是例如与 MSVC 或 ICC 没有。

Compiler Explorer

一般来说,他们抱怨 std::string 提供的构造函数不能真正工作所导致的一些歧义。

此外,如果我在 gcc 上打开 Wconversion,我会遇到分段错误?!

代码有问题吗?这些错误只是编译器错误吗? 如果我将代码更改为不使用模板,它会很好地工作: Compiler Explorer

【问题讨论】:

  • 仅供参考,全部使用static_cast&lt;const basic_string&amp;&gt; 编译,这与构造函数 (7) 完全匹配:en.cppreference.com/w/cpp/string/basic_string/basic_string
  • @RichardCritten:但这会涉及在转换函数中使用对临时对象的引用时未定义的行为。
  • 在您提到的情况下,它被隐式转换为std :: string。在这个隐式转换之后,会调用复制构造函数......但这显然不是我想要的。它应该只调用转换运算符(它可以在没有 static_cast 或 c 样式转换的情况下工作)。

标签: c++ visual-c++ c++14 c++17


【解决方案1】:

不幸的是,标准在这里含糊不清([expr.static.cast]/4,引文省略):

如果存在从eT 的隐式转换序列,或者如果直接初始化对象或类型引用的重载决议,则表达式e 可以显式转换为类型T T 来自 e 将找到至少一个可行的功能。 […] [T] 结果对象直接从e 初始化。 […]

这里的两个启用条件都成立:有一个隐式转换序列(由所需的转换函数调用组成),并且有几个可用于直接初始化的可行函数(因为对于各种单个参数也有隐式转换序列对于std::string 构造函数)。

但是,只有隐式转换序列的复制初始化,它拒绝将ConvSample 转换为(比如)const char*,然后再转换为std::string,这提供了一个明确的产生std::string 的方法:它专门寻找到目标类型的转换函数,虽然它允许 转换为(比如)const std::string&amp;,但常见的实现并不将其解释为意味着转换函数模板也应该为该类型实例化并变得模棱两可。

std::string 的 5 个单参数构造函数(std::string_view-like 类型为 6 个)最终调用的直接初始化是不明确的:ConvSample 当然可以转换为任何参数类型它们中的“成本”相同。

接受这一点的编译器正在应用复制初始化规则(但仍允许explicit 转换)。那些拒绝它的人正在应用直接初始化,我相信这是目前的措辞所要求的。仅在 C++17 中为 CWG242 引入了对隐式转换序列的引用,显然该领域的实现分歧仍然存在。

【讨论】:

  • 我不认为解释 static_cast 的这个问题解释了实现的分歧。通过直接初始化std::string str(aInst); 获得完全相同的结果。 GCC 和 Clang 是否错误地将复制初始化规则应用于直接初始化?也许吧,但我发现它们都有相同的错误是不寻常的。
  • @Brian:这是一个很好的观点; “真正的”直接初始化的行为方式相同,这确实是有道理的,因为这就是 static_cast 应该做的事情。使用explicit 和参数类型的各种组合,我也设法找到了 GCC/Clang 的区别;如果我完善理论,我一定会在这里编辑。
  • @Brian:我是CWG2327,这也涉及新的 C++17 措辞。
猜你喜欢
  • 2022-01-04
  • 1970-01-01
  • 2016-10-25
  • 1970-01-01
  • 2010-10-06
  • 1970-01-01
  • 1970-01-01
  • 2011-03-28
  • 1970-01-01
相关资源
最近更新 更多