I simplified my class MyVector
in C++ by combining the lvalue and rvalue constructors into a single universal reference constructor. However, this change has led to a problem: the template parameter T
of my class cannot be deduced from the universal reference parameter U
in the constructor.
Here’s the definition of my class:
template<typename T>
class MyVector {
public:
std::vector<T> data;
...
template<typename U>
MyVector(U&& data) : data(std::forward<U>(data)) {}
};
The consequence of this limitation is that using my class becomes inconvenient. Instead of being able to instantiate it like this:
MyVector v = std::vector<int>({1, 2, 3});
I am forced to specify the template parameter explicitly:
MyVector<int> v = std::vector<int>({1, 2, 3});
I would like to enforce that std::decay_t<U>
must be a std::vector<T>
and, in turn, deduce T
from U
. It’s important to note that I do not want to simply ignore the definition of this constructor if std::decay_t<U> != std::vector<T>
, which I could achieve using std::enable_if
. Instead, I want to bind std::decay_t<U>
to std::vector<T>
in a way that enforces equality between these types, allowing type deduction to take place. Is there a way to achieve this in C++ using type traits or other techniques?
I tried to solve this problem by creating a method bind
in the class MyVector
that takes one parameter of type std::vector<T>
and passing std::declval<std::decay_t<U>>()
to this function. Unfortunately, this failed with an error indicating that the result of std::declval
must be unused. I have no other ideas on how to bind U
to std::vector<T>
in a way that would allow for type deduction. Is there a way to achieve this in C++ using type traits or other techniques?
You can add a deduction guide.
template <typename U>
MyVector(U) -> MyVector<typename U::value_type>;
You may optionally want to further restrict the constructor to only accept std::vector
.
template<typename U>
requires std::is_same_v<std::decay_t<U>,
std::vector<typename std::decay_t<U>::value_type>>
MyVector(U&& data) : data(std::forward<U>(data)) {}