首页 > 解决方案 > 模棱两可的重载、隐式转换和显式构造函数

问题描述

考虑以下小程序:

#include <vector>

class A {
  int a;
  int b;

 public:
  explicit A() = default;
  A(int _a, int _b) : a(_a), b(_b) {}

  int f(const A& a) { return 0; }
  int f(std::vector<int> a) { return 1; }
};
int g(const A& a) { return 2; }
int g(std::vector<int> a) {  return 3; }

int main() {
  A a(1,2);
  //   a.f({}); //ambiguous according to gcc
  g({}); //ambiguous according to gcc
  return 0;
}

GCC 10.2 拒绝编译它:它说调用g({})并且a.f({})是模棱两可的。Clang 编译这个没有抱怨。

在我看来,g(const A&)不应该在重载决议中考虑,因为不允许从无参数进行隐式转换:A::A()被标记为显式。

我不确定错误不是我的,无论如何,我想找到一个解决方法。

是否有另一个默认生成的构造函数可能是我的问题的根源?

您可以在编译器资源管理器上尝试。

这篇SO 帖子引起了我的注意。它的答案告诉我们哪个编译器是正确的:它是 GCC。但它并没有告诉我们如何使用这些重载规则获得所需的行为。

标签: c++language-lawyerimplicit-conversiondefault-constructor

解决方案


你是对的,它看起来像一个错误。下面注释掉的行由于不应该有歧义的确切原因而无法编译。

使用 std::initializer_list 为您提供了解决方法:

#include <fmt/core.h>
#include <vector>

class A {
  int a;
  int b;

 public:
  explicit A() = default;
  A(int _a, int _b) : a(_a), b(_b) {fmt::print("Aab\n");}

  void f(const A& a) { fmt::print("A\n"); }
  void f(std::vector<int> a) { fmt::print("vector\n"); }
  void f(std::initializer_list<int> l) {
      return f(std::vector<int>(l));
  }
};
void g(const A& a) { fmt::print("A\n"); }
void g(std::vector<int> a) { fmt::print("vector\n"); }
void g(std::initializer_list<int> a) {return g(std::vector<int>(a)); }

int main() {
  A a(1,2);
  A a2 = A();
  //A a3 = {};
  a.f({});
  g({});
  return 0;
}

推荐阅读