我遇到以下代码的编译错误:
class SymbolGroup
{
std::string d_;
public:
SymbolGroup(std::string a):d_(a){}
// explicit operator const std::string&() const { return d_;} // compiles
explicit operator std::string() const { return d_;} // Does not compile
};
inline
bool operator==(const SymbolGroup& lhs, const SymbolGroup& rhs)
{
return static_cast<const std::string&>(lhs) ==
static_cast<const std::string&>(rhs);
}
int main(){
SymbolGroup a("hello");
SymbolGroup b("hello");
if (a==b)
std::cout << "they are the same\n";
return 0;
}
如果用户定义的类型转换行中没有“const”和“&”,则无法使用 --std=c++11 标志在 g++ (4.8) 中进行编译:
错误:类型“std::string&”的引用初始化无效 std::basic_string&}' 来自“const string {aka”类型的表达式 const std::basic_string}’ 显式运算符 std::string&() 常量 { 返回 d_;}
代码在 Clang 上以两种方式编译。哪个编译器是正确的?这段代码应该用
operator std::string()
编译吗?
更新我之前的回答完全错误。道歉!太棒了; clang 接受代码是正确的,gcc 拒绝它是错误的。
首先,来自[expr.static.cast]:
可以使用
形式的 static_cast 将表达式 e 显式转换为类型 T 如果声明static_cast<T>(e)
;对于某些发明的临时变量 t (8.5) 来说是格式良好的。T t(e)
因此,我们尝试从
std::string const&
类型的对象显式直接初始化 SymbolGroup const&
类型的对象。有一节专门讨论通过转换函数初始化引用:“通过转换函数进行直接引用绑定的初始化”[over.match.ref]:
在 8.5.3 中指定的条件下,引用可以直接绑定到左值或类纯右值,即 将转换函数应用于初始值设定项表达式的结果。过载分辨率用于选择 要调用的转换函数。假设“cv1 T”是引用的基础类型 初始化,“cvS”是初始化表达式的类型,其中S是类类型,候选函数 选择如下:
— 考虑S及其基类的转换函数。那些非显式转换 函数 [...] 是候选函数。对于直接初始化,那些显式的 未隐藏在 S 中并产生类型“对 cv2 T2 的左值引用”或“cv2”的转换函数 T2”或“对 cv2 T2 的右值引用”,其中 T2 与 T 类型相同或可以转换 通过限定转换(4.4)输入 T 也是候选函数。
第一部分不适用,因为我们的转换函数是
explicit
,所以我省略了它。第二部分确实如此。我们有 cv1 T 是 const std::string
,所以我们到 std::string
的转换函数是候选函数,因为 std::string
可以通过限定转换转换为 const std::string
。
gcc 在这里是错误的,我提交了 bug 66893,得到了我们自己的 C++ 专家和周围的好人 Jonathan Wakely 以及首席 Clang 开发人员和 C++ 标准编辑 Richard Smith 的确认(在我彻底尴尬地提交了一个 Clang 错误)。
先生,我的答案非常简单。而不是像这样转换为 const 引用作为返回:
return static_cast<const std::string&>(lhs) == static_cast<const std::string&>(rhs);
将您的类型投射到
std::string
:
return static_cast<std::string>(lhs) == static_cast<std::string>(rhs);
并享受工作代码:)
通过对比,我找到了原因。
在 vs 将“c/c++/语言/一致性模式”设置为“Yes(/permissiv-)”
在cmake中添加add_compile_options(“/permissive-”)