强制转换操作符总是有歧义的

Casting operator always ambiguous

本文关键字:歧义 转换 操作符      更新时间:2023-10-16

考虑以下示例:

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
}

当我调用从qm的模糊转换时,它失败了。为什么如此?我真的不明白。我明确地为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 from m -优先选择自定义转换序列;或
  • 使两个转换操作符都为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);

引起相同的诊断

为什么结构有歧义?因为:-

    当然,没有mpf_class(q const &)这样的构造函数
  • 因此,如果存在,则需要从q转换为其他11种类型之一,,由此可以构建mpf_class
  • 但是有两个这样的转换,每个都一样好,多亏了为q提供的两个强制转换操作符。

转换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;
}