铸造操作员总是模棱两可

时间:2015-06-07 15:51:22

标签: c++ casting

考虑以下示例:

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,则可行。为什么这么重要?我怎么能做我想做的事?

2 个答案:

答案 0 :(得分:2)

考虑编译器执行的可能路径:

m temp__(x);

有三个相关的构造函数:

m(int );      // (A)
m(const m& ); // (B)
m(m&& );      // (C)

我们可以通过(A)拨打x --> double --> int,这是用户定义的转化顺序。

我们可以通过(B)拨打(C)x --> m,这也是用户定义的转化顺序。

如果用户定义的转换序列最终调用相同的构造函数,则它们只能是对另一个的首选项。但在这种情况下,他们没有 - 因此编译器无法选择其中一个。因此,含糊不清。

您的替代方案是

  • 直接致电您的运营商(或使其具有某个名称的功能);或
  • 使q继承自m - 派生到基础的转换将优先于用户定义的转换序列;或
  • 制作两个转换运算符explicit - 在这种情况下,只有一个可行的候选者开始,所以不会有歧义。

答案 1 :(得分:0)

当我使用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_classtypedef __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;
}