I have the following code:
#include <iostream>
#include <typeinfo>
template <typename T>
struct A : T {
template <typename ...Args>
A(Args&&... params) : T(std::forward<Args>(params)...), x(0) {
std::cout << "Member 'x' was default constructed\n";
}
template <typename O, typename ...Args, typename = typename std::enable_if<std::is_constructible<int,O>::value>::type>
A(O o, Args&&... params) : T(std::forward<Args>(params)...), x(o) {
std::cout << "Member 'x' was constructed from arguments\n";
}
int x;
};
struct B{
B(const char*) {}
};
int main() {
A<B> a("test");
A<B> y(3, "test");
return 0;
}
It works fine, and prints
Member 'x' was default constructed
Member 'x' was constructed from arguments
However, if the first argument of the second overload is a reference, suddenly the second overload is never taken, and compilation fails:
template <typename O, typename ...Args, typename = typename std::enable_if<std::is_constructible<int,O>::value>::type>
A(O& o, Args&&... params) : T(std::forward<Args>(params)...), x(o) {
std::cout << "Member 'x' was constructed from arguments\n";
} // Note the O& in the arguments
Why is this? Is it possible to fix it and avoid copies?
EDIT: Using an universal reference apparently makes it work again. A const
reference, which is what I'd actually like, does not work either.
In addition, even saving the input parameter into a separate value (avoiding an rvalue) will still not work:
int main() {
double x = 3.0;
A<B> y(x, "test"); // Still not working
return 0;
}