【发布时间】:2017-09-17 05:52:47
【问题描述】:
所以我有一个提供字符串类型的现有库。
它像这样隐式转换 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;}
};
它还有其他方法,但我认为它们并不重要。这些方法有实体,但我的问题不涉及它们,所以我已经将它们存根。
我想做的是创建一个可以与上述类型相对互换使用的新类型,以及"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);
}
如果我用上面的TypeIDoNotOwn 替换TypeIOwn,它会编译。如何在不修改TypeIDoNotOwn 的情况下使用TypeIOwn 编译它?并且无需在声明时引入除类型更改之外的任何强制转换或更改?
我的第一次尝试看起来有点像这样:
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;}
};
但我得到了一系列模棱两可的重载:
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;}
和
/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*) {} ^
在我的“真实”代码中,我有其他运算符,例如 += 和 ==,它们也有类似的问题。
实际问题的范围很大;数百万行代码,我想在数千个位置将 TypeIDoNotOwn 换成 TypeIOwn,而不是在数百个其他位置。在数千个位置,它们以一种导致转换模糊的方式进行交互。
我已经解决了一个函数在它发生的 100 个点上使用TypeIDoNotOwn& 的问题,方法是用一个宏包装它,该宏创建一个临时对象,该对象从TypeIOwn 创建一个TypeIDoNotOwn,返回一个引用然后,当临时对象被销毁时,将其复制回TypeIOwn。我想避免必须进行类似的扫描来处理==、+=、=、复制构造和类似情况。
如果我尝试删除 operator TypeIDoNotOwn 以消除歧义,则需要进行转换的其他情况将无法正常工作(因为它需要 2 个用户定义的结构才能从 TypeIOwn 到 TypeIDoNotOwn) ,然后需要进行显式转换(在许多 100 或 1000 个位置)
如果我可以让一种转化看起来比另一种更糟糕,它会起作用。如果做不到这一点,我可以尝试通过重载具有完全匹配的免费TypeIDoNotOwn == TypeIOwn 运算符(其他情况类似)来修复非operator= 和复制构造情况,但这不会让我构造、函数调用和任务。
【问题讨论】:
-
我担心如果不修改使用类型(此处为
main)或您不拥有的类型的代码,这将不会成功.. 可惜我们没有免费的(非成员)用户定义的转换运算符;与他们一起,可能会利用 ADL 来解决这种歧义。 -
注意:提供到
char const (&)[SIZE]的转换不起作用(初始化和TypeIDoNotOwn构造的衰减相同)。 -
struct TypeIDoOwn : TypeIDoNotOwn?
标签: c++ c++14 assignment-operator c++17 ambiguous