Consider the following code:
#include <vector>
#define BROKEN
class Var {
public:
#ifdef BROKEN
template <typename T>
Var(T x) : value(x) {}
#else
Var(int x) : value(x) {}
#endif
int value;
};
class Class {
public:
Class(std::vector<Var> arg) : v{arg} {}
std::vector<Var> v;
};
Clang++ (7.0.1) compiles this without errors whether or not BROKEN
is defined, but g++ (8.2.1) raises an error if BROKEN
is defined:
main.cpp:9:20: error: cannot convert ‘std::vector<Var>’ to ‘int’ in initialization
Var(T x) : value(x) {}
^
As far as I know, the uniform intialization used here should select the std::vector(std::vector&&)
constructor in both cases; apparently, however, g++
instead sees the {arg}
as an initializer list and tries to initialize the first element of v
with Var
applied to a vector, which won't work.
If BROKEN
is not defined, g++ is apparently smart enough to realize that the initializer_list overload isn't going to work.
Which is the correct behavior, or are both allowed by the standard?
BROKEN defined gcc
BROKEN not defined gcc
BROKEN defined clang
Here is are two ways to fix that issue:
class Var {
public:
#ifdef BROKEN
template <typename T>
Var(T x, typename std::enable_if<std::is_convertible<T, int>::value>::type* = nullptr) : value(x) {}
#else
Var(int x) : value(x) {}
#endif
int value;
};
Live demo.
Or:
class Class {
public:
Class(std::vector<Var> arg) : v(arg) {}
std::vector<Var> v;
};
Live demo.
Now apparently in case of gcc tries use template parameter as initialization list. When braces are used and initialization list is defined, initialization list has higher priority then copy constructor.
So adding proper enable_if
solves the problem since it protects from creating initialization list version of constructor. In C++20 concepts will solve this in better way.
And when parenthesis instead braces are used to initialize v
initialization list is not preferable.
I'm not sure who is right (IMO clang, but this is just a gut feeling). Maybe someone who knows standard better can tell.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With