Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

gcc

clang

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.

like image 857
Timo Avatar asked Nov 08 '22 11:11

Timo


1 Answers

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.

like image 197
1stCLord Avatar answered Nov 14 '22 23:11

1stCLord