用户定义的转换函数和转换为引用

问题描述 投票:0回答:3

我遇到以下代码的编译错误:

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()
编译吗?

c++ type-conversion
3个回答
5
投票

更新我之前的回答完全错误。道歉!太棒了; clang 接受代码是正确的,gcc 拒绝它是错误的。


首先,来自[expr.static.cast]:

可以使用

static_cast<T>(e)
形式的 static_cast 将表达式 e 显式转换为类型 T 如果声明
T t(e)
;对于某些发明的临时变量 t (8.5) 来说是格式良好的。

因此,我们尝试从

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 错误)。


1
投票

先生,我的答案非常简单。而不是像这样转换为 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);

并享受工作代码:)


0
投票

通过对比,我找到了原因。

在 vs 将“c/c++/语言/一致性模式”设置为“Yes(/permissiv-)”

在cmake中添加add_compile_options(“/permissive-”)

© www.soinside.com 2019 - 2024. All rights reserved.