Timo
Timo

Reputation: 1814

Gcc fails with "call of overload is ambignuous" while clang does not

I have the following code:

#include <experimental/string_view>

struct b_symbol {
    template <typename T>
     explicit b_symbol(T&& symbol)
        : symbol(std::forward<T>(symbol)) {
    }

    std::experimental::string_view symbol;
};

struct b_utf8 {
    template <typename T>
    explicit b_utf8(T&& value)
        : value(std::forward<T>(value)) {
    }

    std::experimental::string_view value;

};

struct value {
    explicit value(b_utf8) {}
    explicit value(b_symbol) {}

};

int main() {
    value v({b_utf8("test")});
}

You can try it on godbolt.

If I compile it with clang (3.8.0):
clang++ oload.cpp -std=c++1y
everything runs fine.

If i compile it with gcc (6.1.1 20160602)
g++ oload.cpp -std=c++1y
I get:

oload.cpp: In function ‘int main()’:
oload.cpp:30:29: error: call of overloaded ‘value(<brace-enclosed initializer list>)’ is ambiguous
     value v({b_utf8("test")});
                             ^
oload.cpp:25:14: note: candidate: value::value(b_symbol)
     explicit value(b_symbol) {}
              ^~~~~
oload.cpp:24:14: note: candidate: value::value(b_utf8)
     explicit value(b_utf8) {}
              ^~~~~
oload.cpp:23:8: note: candidate: constexpr value::value(const value&)
 struct value {
        ^~~~~
oload.cpp:23:8: note: candidate: constexpr value::value(value&&)

Why that difference?
Is the behavior of gcc correct?

EDIT: As slavanap pointed out in his answer, the error can be circumvented by removing the curly braces on call-site. Non the less I would like to know why the compilers behave differently.

Upvotes: 5

Views: 159

Answers (2)

1stCLord
1stCLord

Reputation: 880

You are passing an initialiser list to a constructor that explicitly takes either a b_utf8 or a b_symbol, neither is correct.

You must define a constructor that takes an initialiser list if you don't want to use implicit casts.

I think this is in the process of being changed for C++17 and you will be allowed to do it the clang way then.

EDIT: Interestingly

struct  b_utf8 {

  b_utf8() = default;
  //b_utf8(){}
};

struct value {
  explicit value(b_utf8) {}
};

int main() {
    value v({b_utf8()});
}

compiles but

struct  b_utf8 {

  //b_utf8() = default;
  b_utf8(){}
};

struct value {
  explicit value(b_utf8) {}
};

int main() {
    value v({b_utf8()});
}

fails overload resolution. I'm not sure why, as far as I can tell overload resolution should behave the same in those two cases.

Upvotes: 1

Vyacheslav Napadovsky
Vyacheslav Napadovsky

Reputation: 907

In the error it says <brace-enclosed initializer list>.

    // Why not just try to call 
    value v(b_utf8("test"));
    // instead
    value v({b_utf8("test")});
    // ?

Upvotes: 0

Related Questions