Ambiguous overloads, implicit conversion and explicit constructors [duplicate]
Asked Answered
B

1

12

Consider the following little program:

#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 refuse to compile it: it says the call to g({}) and a.f({}) are ambiguous. Clang compile this without complaining.

It seems to me that g(const A&) shouldn't be considered in overload resolution because implicit conversion from no arguments is not allowed: A::A() is marked explicit.

I am not confident that the fault isn't mine and, in any case, I'd like to find a workaround.

Is there another default generated constructor that could be the source of my problem?

You can try it on the compiler explorer.

This SO post was brought to my attention. Its answer tells us which compiler is right: it's GCC. But it does not tell us how to obtain the desired behavior with those overload rules.

Barbrabarbuda answered 16/2, 2021 at 16:33 Comment(10)
I would change default to explicit in titleCadelle
I'm not convinced you're right. It seems possible to me that {} might be allowed to use an explicit constructor, I'm not sure. It's definitely not an implicit conversion...Gereron
@Yakk done. finding a good title is always a struggle.Barbrabarbuda
I would say gcc bug. especially when clang/msvc accept it Demo.Arapaho
with extra int argument (instead of default constructor), only clang accepts it Demo...Arapaho
Interesting, if you comment out std::vector variant gcc complains that explicit ctor of A cannot be used.Doubleganger
@MooingDuck I'm not convinced i'm right either.Barbrabarbuda
Btw you could minimize your example removing class A members, another ctor, methods etc ideone.com/tgyAfgDoubleganger
If non default ctor is used then gcc compiles just fine - godbolt.org/z/P3aYYEDoubleganger
GCC is correct - see the dup.Palfrey
F
4

You're right that it seems like a bug. The commented out line below fails to compile for the exact reason that there should be no ambiguity.

Got a workaround for you using 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;
}
Fireworks answered 16/2, 2021 at 20:22 Comment(4)
Thank you Mark. Now i guess i have a bug report to submit.Barbrabarbuda
Nice find - please share the bug link if you report one. I'd like to follow along!Fireworks
See latest edit, seems it ain't a GCC bug after all.Barbrabarbuda
OK, I guess I have to concede to Bjarne!Fireworks

© 2022 - 2024 — McMap. All rights reserved.