默认构造函数中的歧义

Ambiguity in default constructor

我试图了解 C++11 中引入的构造函数的一些默认选项,所以我正在阅读一些 notes from Bjarne

在此页面上,他是以下示例:

struct Z {
    // ...

    Z(long long);     // can initialize with an long long
    Z(long) = delete; // but not anything less
};

他指出 Z 可以用 long long 构造,但 也一样 。这个措辞对我来说有点不清楚。我假设 "anything less" 可能指代 space 少于 long long 的任何东西。

我在我的机器上测试了一些尺寸,发现 long long 需要 8 个字节,long double 需要 16 个字节,所以我假设用 long double 构造就可以了,并且会简单地截断小数部分并将其强制为 long long.

我写了这个:

class Foo {
  public:
    Foo(long long x) : x(x) {}
    Foo(long x) = delete;
  private:
    long long x;
};

int main() {
  Foo foo1(100LL); // Compiles fine
  // Foo foo2(100L); // Compile error - cannot construct with smaller than `long long`. This is obvious
  Foo foo3(42.0L); // This causes an error

  return 0;
}

令我惊讶的是,上面的代码导致了一个错误:

error: call of overloaded 'Foo(long double)' is ambiguous Foo foo3(42.0L);

这对我来说似乎很明确。为什么编译器不能解决这个问题?

已删除的构造函数已声明,但未定义。而不是 undefined,而是 deleted

当编译器进行函数重载决策时,它会使用已声明的兼容函数的集合,其中也包括已删除的函数。如果重载解析恰好 select 一个已删除的函数,那么你会得到一个编译器错误。如果重载决议无法决定最佳函数,您也会收到编译器错误,即使歧义来自已删除的函数。

您可能认为删除的函数不参与重载决议会更好。但这用处不大。如果不想Foo(long)参与重载决议,就不写了!

这类似于 public/private 函数的重载。即使从 class 外部调用,public 和私有函数也参与重载决议:

class Foo
{
public:
    void fun(long long);
private:
    void fun(long);
};
int main()
{
    Foo f;
    f.fun(100LL); //ok
    f.fun(100L); //error: fun(long) is private
    f.fun(1.0); //error: call is ambiguous
}