创建兼容的String对象

Yak*_*ont 10 c++ ambiguous assignment-operator c++14 c++17

所以我有一个提供字符串类型的现有库.

它隐式转换为C样式字符串,如下所示:

struct TypeIDoNotOwn {
  TypeIDoNotOwn() {}
  TypeIDoNotOwn(TypeIDoNotOwn const&) {}
  TypeIDoNotOwn(char const*) {}

  TypeIDoNotOwn& operator=(TypeIDoNotOwn const&) {return *this;}
  TypeIDoNotOwn& operator=(char const*) {return *this;}

  operator char const*() const {return nullptr;}
};
Run Code Online (Sandbox Code Playgroud)

它有其他方法,但我不认为它们很重要.这些方法有机构,但我的问题不涉及它们,所以我把它们剔除了.

我想要做的是创建一个可以与上述类型相对可互换使用的新类型,并使用"raw string constants".我希望能够获取一个实例TypeIDoNotOwn,并替换它TypeIDoOwn,并编译代码.

举个例子,这套操作:

void test( TypeIDoNotOwn const& x ) {}

int main() {
  TypeIOwn a = TypeIDoNotOwn();
  TypeIDoNotOwn b;
  a = b;
  b = a;
  TypeIOwn c = "hello";
  TypeIDoNotOwn d = c;
  a = "world";
  d = "world";
  char const* e = a;
  std::pair<TypeIDoNotOwn, TypeIDoNotOwn> f = std::make_pair( TypeIOwn(), TypeIOwn() );
  std::pair<TypeIOwn, TypeIOwn> g = std::make_pair( TypeIDoNotOwn(), TypeIDoNotOwn() );
  test(a);
}
Run Code Online (Sandbox Code Playgroud)

如果我TypeIOwnTypeIDoNotOwn上面的替换,它编译.如何在TypeIOwn 修改的情况下进行编译TypeIDoNotOwn?并且不必在声明点引入任何演员表或变更以外的类型更改?

我的第一次尝试看起来有点像这样:

struct TypeIOwn {
  TypeIOwn() {}
  operator char const*() const {return nullptr;}
  operator TypeIDoNotOwn() const {return {};}
  TypeIOwn( TypeIOwn const& ) {}
  TypeIOwn( char const* ) {}
  TypeIOwn( TypeIDoNotOwn const& ) {}
  TypeIOwn& operator=( char const* ) {return *this;}
  TypeIOwn& operator=( TypeIOwn const& ) {return *this;}
  TypeIOwn& operator=( TypeIDoNotOwn const& ) {return *this;}
};
Run Code Online (Sandbox Code Playgroud)

但是我得到了一系列模糊的重载:

 main.cpp:31:4: error: use of overloaded operator '=' is ambiguous (with operand types 'TypeIDoNotOwn' and 'TypeIOwn')
         b = a;
         ~ ^ ~
 main.cpp:9:17: note: candidate function
         TypeIDoNotOwn& operator=(TypeIDoNotOwn const&) {return *this;}
                        ^
 main.cpp:10:17: note: candidate function
         TypeIDoNotOwn& operator=(char const*) {return *this;}
Run Code Online (Sandbox Code Playgroud)

 /usr/include/c++/v1/utility:315:15: error: call to constructor of 'TypeIDoNotOwn' is ambiguous
             : first(_VSTD::forward<_U1>(__p.first)),
               ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 main.cpp:40:51: note: in instantiation of function template specialization 'std::__1::pair<TypeIDoNotOwn, TypeIDoNotOwn>::pair<TypeIOwn, TypeIOwn>' requested here
       std::pair<TypeIDoNotOwn, TypeIDoNotOwn> f = std::make_pair( TypeIOwn(), TypeIOwn() );
                                                   ^
 main.cpp:7:7: note: candidate constructor
       TypeIDoNotOwn(TypeIDoNotOwn const&) {}
       ^
 main.cpp:8:7: note: candidate constructor
       TypeIDoNotOwn(char const*) {}
       ^
Run Code Online (Sandbox Code Playgroud)

在我的"真实"的代码,我有其他运营商,如+===,有类似的问题.

真正问题的范围很大; 数以百万计的代码行,我想在数千个位置换掉TypeIDo的TypeIDoNotOwn,而不是数百个其他位置.在数千个位置,他们以导致转换模糊的方式进行交互.

我已经通过TypeIDoNotOwn&一个宏来创建一个临时对象来创建一个TypeIDoNotOwn来自TypeIOwn,返回对它的引用,然后当临时对象被销毁时将其复制回来解决了函数在100个点发生的问题.到了TypeIOwn.我想避免做类似的扫描处理==,+=,=,复制建设,类似的情况.

实例.

如果我试图删除operator TypeIDoNotOwn以消除这种歧义,那么转换需要发生的其他情况就不能正常工作(因为它需要2个用户定义的构造来TypeIOwn实现TypeIDoNotOwn),然后需要进行显式转换(在许多情况下) 100或1000个地点)

如果我可以让一个转换看起来比另一个更糟糕,它会起作用.如果做不到这一点,我可以尝试operator=通过重载一个TypeIDoNotOwn == TypeIOwn具有精确匹配的自由运算符来修复非和复制构造的情况(和其他情况类似),但这不会让我得到构造,函数调用和赋值.

Bar*_*rry 2

通常需要注意的是,这是 C++,并且肯定有一些聪明的解决方法......不。


让我们看一下您的用例。您希望复制初始化和复制分配都起作用:

TypeIOwn a = ...;
TypeIDoNotOwn b = a;  // (*)
TypeIDoNotOwn c;
c = a;                // (*)
Run Code Online (Sandbox Code Playgroud)

这就需要:

operator TypeIDoNotOwn();
Run Code Online (Sandbox Code Playgroud)

如果您刚刚提供operator const char*(),则分配将起作用,但复制初始化将失败。如果您提供了两者,那么它是不明确的,因为没有办法强制一个转换优先于另一个(强制转换排序的唯一真正方法是创建类型层次结构,但您不能继承,所以您不能const char*真正强制其工作)。

一旦我们开始只使用一个转换函数,示例列表中唯一不起作用的代码是:

const char* e = a; // error: no viable conversion
Run Code Online (Sandbox Code Playgroud)

此时,您必须添加一个成员函数:

const char* e = a.c_str();
Run Code Online (Sandbox Code Playgroud)

两种pair结构都可以与一个转换函数配合使用。但仅仅通过排除法,我们就无法两者兼得。