强制转换操作符总是有歧义的
Casting operator always ambiguous
考虑以下示例:
struct m
{
m(int ) { }
};
class q
{
public:
int i;
q(int i)
{
this->i = i;
}
operator double()
{
return (double) i;
}
operator m()
{
return (m)i;
}
};
int main()
{
q x(1);
(m)x; // error: ambiguous
}
当我调用从q
到m
的模糊转换时,它失败了。为什么如此?我真的不明白。我明确地为m
添加了一个强制转换操作符!为什么要模棱两可呢?但是,如果我移除对double
的强制转换,这就有效了。为什么这很重要?我怎样才能做我想做的事?
考虑编译器可能采取的路径:
m temp__(x);
有三个相关的构造函数:
m(int ); // (A)
m(const m& ); // (B)
m(m&& ); // (C)
我们可以通过x --> double --> int
调用(A)
,这是一个用户定义的转换序列。
我们可以通过x --> m
调用(B)
或(C)
,这也是一个用户定义的转换序列。
用户定义的转换序列只有在调用相同的构造函数时才能成为另一个转换序列的首选项。但在这种情况下,它们没有——所以编译器没有办法偏爱其中一个。因此,模糊。
你可以选择
- 直接调用你的操作符(或者让它成为一个函数);或
- make
q
inherit fromm
-优先选择自定义转换序列;或 - 使两个转换操作符都为
explicit
-在这种情况下,只有一个可行的候选开始,因此不会有歧义。
当我用g++ 5.1编译你的程序时,我得到:
/home/imk/develop/so/mpf_cast/main.cpp:35:25: error: call of overloaded ‘__gmp_expr(q&)’ is ambiguous
cout << (mpf_class) x << endl;
^
/home/imk/develop/so/mpf_cast/main.cpp:35:25: note: candidates are:
In file included from /home/imk/develop/so/mpf_cast/main.cpp:2:0:
/usr/include/gmpxx.h:1883:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(double)
__gmp_expr(double d) { mpf_init_set_d(mp, d); }
^
/usr/include/gmpxx.h:1880:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(float)
__gmp_expr(float f) { mpf_init_set_d(mp, f); }
^
/usr/include/gmpxx.h:1876:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(long unsigned int)
__gmp_expr(unsigned long int l) { mpf_init_set_ui(mp, l); }
^
/usr/include/gmpxx.h:1873:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(long int)
__gmp_expr(signed long int l) { mpf_init_set_si(mp, l); }
^
/usr/include/gmpxx.h:1869:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(short unsigned int)
__gmp_expr(unsigned short int s) { mpf_init_set_ui(mp, s); }
^
/usr/include/gmpxx.h:1866:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(short int)
__gmp_expr(signed short int s) { mpf_init_set_si(mp, s); }
^
/usr/include/gmpxx.h:1862:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(unsigned int)
__gmp_expr(unsigned int i) { mpf_init_set_ui(mp, i); }
^
/usr/include/gmpxx.h:1859:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(int)
__gmp_expr(signed int i) { mpf_init_set_si(mp, i); }
^
/usr/include/gmpxx.h:1855:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(unsigned char)
__gmp_expr(unsigned char c) { mpf_init_set_ui(mp, c); }
^
/usr/include/gmpxx.h:1852:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(signed char)
__gmp_expr(signed char c) { mpf_init_set_si(mp, c); }
^
/usr/include/gmpxx.h:1837:3: note: __gmp_expr<__mpf_struct [1], __mpf_struct [1]>::__gmp_expr(const __gmp_expr<__mpf_struct [1], __mpf_struct [1]>&)
__gmp_expr(const __gmp_expr &f)
^
问题强制转换表达式(mpf_class) x
需要一个mpf_class
(typedef __gmp_expr<mpf_t, mpf_t> mpf_class
)从q
构造。所以你不妨考虑
q x(1);
mpf_class m(x);
引起相同的诊断
为什么结构有歧义?因为:-
- 当然,没有
- 因此,如果存在,则需要从
q
转换为其他11种类型之一,,由此可以构建mpf_class
。 - 但是有两个这样的转换,每个都一样好,多亏了为
q
提供的两个强制转换操作符。
mpf_class(q const &)
这样的构造函数转换operator double()
可以满足11个构造函数中的第一个operator mpf_class()
可以满足最后一种。编译器没有依据
如果牺牲一个或多个强制转换操作符,问题就会消失。如果你必须同时拥有它们,那么你也可以通过制造它们来解决它explicit
,以便编译器不会考虑调用转换,除非它是显式调用的:
explicit operator double()
{
return (double)i;
}
explicit operator mpf_class()
{
return (mpf_class)i;
}
然后你会发现,例如:
int main()
{
q x(1);
mpf_class mpf(x); // via `explicit operator mpf_class()`
double d(x); // via `explicit operator double()`
// d = q(2); <- does not compile
d = static_cast<double>(q(2));
// mpf = q(2); <- does not compile
mpf = static_cast<mpf_class>(q(2));
return 0;
}
顺便说一下:
- 强制转换操作符应该是
- 在函数中,将返回值强制转换为是多余的存在隐式转换时的返回类型。
const
:
explicit operator double() const
{
return i;
}
explicit operator mpf_class() const
{
return i;
}
相关文章:
- 为什么下面带有非常量转换函数的代码没有歧义?
- 如何在模板化转换运算符中消除此构造的歧义?
- 函数调用歧义(用户定义的转换和 Derived2Base 指针转换)
- C++中的重载歧义,用于自动将对象转换为"printable"格式
- 资格转换的歧义
- 在隐式转换后的智能指针上删除函数调用中的歧义
- 解决隐藏歧义的不明确用户定义转换
- 为什么我总是必须除以 49 才能得到二进制转换器 + cout 歧义的正确答案?
- 转换运算符重载歧义,编译器不同
- 如何解决转换构造函数和普通构造函数之间的歧义
- 转换 - 错误 E2015,AnsiString(char) 和 AnsiString(short) 之间的歧义
- 调用函数的歧义.隐式转换
- C++11:在按值传递参数初始化时转换构造函数和转换函数之间的歧义
- g++和clang++-删除由重载转换运算符歧义获取的指针
- 安全布尔多次转换歧义
- 当目标类有多个构造函数时,消除强制转换操作符的歧义
- 在将派生类指针转换为基类时,基类有歧义
- 歧义调用(从char*到lambda与std::string的转换)
- 运算符=与转换运算符结合时的歧义
- 转换运算符重载 - 函数歧义