【问题标题】:'operator =' is ambiguous for std::string'operator =' 对于 std::string 不明确
【发布时间】:2016-10-07 21:39:17
【问题描述】:

我正在尝试使用自己的演员表操作符编写一个类,但我遇到了多个 operator=s 的问题

我设法用下面的小代码重现了这个问题

#include <string>

class X
{
public:
  operator const char*() const {
    return "a";
  }
  operator std::string() {
    return "c";
  }
};

void func( )
{
  X x;
  std::string s = "";
  s = x;
}

我知道std::basic_string 有多个赋值运算符,这就是编译器感到困惑的原因。

如果我删除任何一个强制转换运算符,它会起作用,但我想知道是否有办法保留两个运算符。

我的班级将根据演员返回不同的值。

我也可以使用static_cast&lt;std::string&gt;(x) 强制转换,但我想知道是否有一种方法可以不使用静态转换?

【问题讨论】:

  • s = std::string(x) 怎么样?
  • 是的,演员表会起作用,(如我的帖子中所述),但我的问题更多是如果我可以提示编译器使用什么,这样我就不需要使用演员表本身.
  • 演员表不正是“对编译器的提示”吗?
  • 是的,当然,你是对的,但我想你明白我的意思。如果 s 被定义为 std::string 我希望编译器使用 operator std::string() 而无需强制转换
  • 问题是std::string 有两个匹配的构造函数,并且语言中没有规则赋予复制构造函数优先于另一个。没有办法强加一个我知道的。

标签: c++ c++11


【解决方案1】:

作为KerrekSB suggested,你可以使用

s = std::string(x);

或者,您可以执行强制转换:

s = (std::string) x;
// or
s = static_cast<std::string>(x);

第三种选择(由于可读性问题,我希望不会经常看到)是直接访问运算符:

s = x.operator std::string();

如果您愿意权衡稍微不同的 API(并修复任何潜在的损坏),您可以执行 Roberto suggested 的操作并强制显式转换 just const char *类型运算符:

class X
{
public:
  explicit operator const char*() const {
    return "a";
  }
  operator std::string() {
    return "c";
  }
};

这告诉编译器只允许隐式转换为std::string,并要求您在要调用该特定运算符时显式转换为const char *


最后一件事要注意:如果您正在设计其他类或方法来使用这个特定的类,另一件要尝试的事情是通过为 class X 提供重载而不是转换 @987654331 来反转它们的使用方式@ 给别的东西。

考虑让您的 API 工作的其他方式总是好的。

【讨论】:

  • 形式上,std::string(x) 也是一个cast(用函数表示法编写)。
  • @AnT std::string(x) 调用构造函数并且不执行实际的强制转换——编译器可能会优化它,当然,但从语义上讲,这不是正在发生的事情。
  • 所以? (std::string) x 也调用构造函数。是的,std::string(x) 是一个演员表,完全符合语言标准中的定义。 cast 是语言的纯句法元素。强制转换的语义归结为类型转换的语义。后者取决于所涉及的类型。该语言实际上明确表示具有单个参数的功能符号转换等效于具有相同参数的经典转换符号。 IE。 std::string(x) cast 被定义为等同于(std::string) x cast。
  • 此外,在 C++ 中,std::string()std::string(20, ' ') 也是通过相同的 函数符号 表示的 casts,即使它们具有零或() 中有多个参数。它们调用构造函数的事实正是这些强制转换在 C++ 中工作所必需的。构造函数调用与 cast 的概念没有任何冲突。作为另一个相关说明,C++ 中基本static_cast&lt;T&gt;(e) 的效果也是通过初始化T t(e) 定义的,即在类类型的情况下调用构造函数。
  • 出于这个原因,我不清楚您的“语义上这不是正在发生的事情”这句话应该是什么意思。对于演员表,你认为在语义上应该发生什么?当语言标准将这两种形式定义为等效时,这(无论是什么)如何可能有助于区分 (std::string) xstd::string(x)
【解决方案2】:

如果您在 char* 转换中使用 explicit 关键字,您将默认转换为 std::string。

class X
{
public:
    explicit operator const char*() const {
        return "a";
    }
    operator std::string() {
         return "c";
    }
};

之后你的演员表:

X x;
std::string s = "";
s = x;

会成功(如果你的班级的用户想要使用其他演员表,他需要指定 char* 演员表)

无论如何,作为您班级的用户,我宁愿两个强制转换都是显式的,所以我知道何时进行强制转换

【讨论】:

  • 这也是一个很好的选择,尽管它会稍微改变 API 的语义并且可能会导致代码损坏(不过这可能是一个很好的权衡)。没想到。
  • 你说得对@Qix,我更喜欢两个演员都是明确的,但我认为西蒙应该决定
  • const char *c = x; 将不再以这种方式工作。您只是在反过来破坏 api。
  • @skypjack 因此我的评论。
猜你喜欢
  • 2021-12-10
  • 1970-01-01
  • 2011-11-09
  • 2023-03-21
  • 2020-05-08
  • 1970-01-01
  • 2020-01-09
  • 2011-02-18
相关资源
最近更新 更多