Search code examples
c++templatesrvalue-reference

Universal reference in constructor with type deduction


How one can use universal reverence in constructor in a templated class with type deduction. I tried all the options and nothing worked.

Consider example:

#include <vector>

template<class T> struct A {
    A(T&& a) {  }
};

template<class T> struct B {
    B(T& a) { }
};

template<class T> struct C {
    template<class T2> C(T2&& a) {}
};

template<class T> void foo(T&& a) { }

auto get_r_value() {
    return std::vector<int>(100);
}

std::vector<int>& get_l_value() {
    static std::vector<int> v(100);
    return v;
}

int main() {
    foo(get_r_value()); // ok
    foo(get_l_value()); // ok

    A a1(get_l_value()); // error!
    A a2(get_r_value()); // ok

    B b1(get_l_value()); // ok
    B b2(get_r_value()); // error!

    C c1(get_l_value()); // error!
    C c2(get_r_value()); // error!
}

Solution

  • If you really want to use a universal reference, you have to go with struct C, because in A you actually declare a rvalue reference, not a forwarding (universal) reference.

    You can fix the deduction of C with a user defined deduction guide

    template <typename T>
    C(T&&) -> C<std::remove_cvref_t<T>>;
    

    Example

    Note that deduction guides require C++17