static_cast:转换函数模板-它们确实有效吗?

Ber*_*nns 6 c++ visual-c++ c++14 c++17

据我阅读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;
}
Run Code Online (Sandbox Code Playgroud)

它与Clang等某些编译器完美配合。但是,例如,没有MSVC或ICC。

请参阅编译器资源管理器

通常,他们抱怨由std :: string提供的未真正起作用的构造函数引起的歧义。

另外,如果我在gcc上启用Wconversion,会遇到分段错误吗?

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

Dav*_*ing 2

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

\n\n
\n

如果存在 from to 的隐式e转换序列,或者如果对象直接初始化或类型引用from的重载决策将找到至少一个可行的函数,则可以将表达式显式转换为类型。[\xe2\x80\xa6] [T]结果对象是直接初始化的TeTTee. [\xe2\x80\xa6]

\n
\n\n

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

\n\n

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

\n\n

最终调用的直接初始化在std::string\xe2\x80\x99s 5 个单参数构造函数(6 个类似std::string_view类型)中是不明确的:ConvSample当然可以在相同的 \xe2\ 处转换为其中任何一个的参数类型x80\x9c成本\xe2\x80\x9d。

\n\n

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

\n

  • @Brian:这是一个好点;“真正的”直接初始化的行为方式相同是有道理的,因为这就是 `static_cast` 应该做的事情。通过尝试“显式”和参数类型的各种组合,我也成功地找到了 GCC/Clang 的区别;如果我完善理论,我肯定会在这里编辑。 (2认同)