static_cast:转换函数模板——它们真的有效吗

static_cast : Conversion function templates - are they really working?

本文关键字:有效 真的 函数模板 cast 转换 static      更新时间:2023-10-16

就我阅读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没有。

请参阅编译器资源管理器

通常,他们抱怨由于std::string提供的构造函数不能真正工作而导致的一些歧义。

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

代码中有什么错误吗?这些错误只是编译器错误吗?如果我将代码更改为不使用模板,则效果非常好:编译器资源管理器

不幸的是,这里的标准很模糊([expr.static.cast]/4,省略引用(:

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

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

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

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

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