Variadic template constructor selection fails when argument is a reference

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 great 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 this and avoid copying?

EDIT: Using a universal link seems to make it work again. The link constthat I really like doesn't work either.

In addition, even saving the input parameter to a separate value (rvalue exception) will still not work:

int main() {
    double x = 3.0;
    A<B> y(x, "test"); // Still not working

    return 0;
}
+4
source share
1

?

:

template <typename O>
A(O& o);

:

A{3};

O int, :

A(int& o);

, rvalue ( 3, ,) const const, .

?

O , forward x ( , int ):

template <typename O>
A(O&& o) : x{std::forward<O>(o)} {}

const lvalue ( rvalues ​​ ):

template <typename O>
A(const O& o) : x{o} {}

, const ( ), . , ( rvalue) .

, , , , .

r int&& rvalues, const int&.

lvalue int& -const lvalues ​​(, x), const int&.

, , , , :

template <typename... Args>
A(Args&&... params);

template <typename O, typename... Args>
A(const O& z, Args&&... params);

. :

double x = 3.0;
A a(x, "test");

:

A(double&, const char (&)[5]);

A(const double&, const char (&)[5]);

( const).

- , O ( , , const lvalue), , int ( ):

template <typename T>
struct A : T
{
    template <typename Arg, typename... Args, typename = typename std::enable_if<!std::is_constructible<int, Arg>::value>::type>
    A(Arg&& param, Args&&... params) : T(std::forward<Arg>(param), 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(const O& o, Args&&... params) : T(std::forward<Args>(params)...), x(o) {
        std::cout << "Member 'x' was constructed from arguments\n"; 
    }

    int x;
};

DEMO

+8

All Articles