4

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}); 

Problem:

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?

What I have tried:

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?

6
  • 1
    "I do not want to simply ignore the definition of this constructor if std::decay_t<U> != std::vector<T>" and "I want to bind std::decay_t<U> to std::vector<T> in a way that enforces equality between these types" I need to admit that I don't understand the problem. These two sentences seem to contradict each other in my opinion. Cound you add some examples of initialization and describe what should be the outcome. Would user-defined deduction guides work for you? Live demo: godbolt.org/z/nrEfMGhs4 Commented Oct 28, 2024 at 6:54
  • Could you give an example where T and U should work together and one where they shouldn't? Commented Oct 28, 2024 at 7:03
  • @DanielLangr In your example, you defined separate deduction guides for lvalue and rvalue arguments. I could define two separate constructors as well, but that solution isn't better. What I’m looking for is a way to enforce that the constructor parameter is a std::vector<T> and deduce T without needing those separate definitions. Commented Oct 28, 2024 at 7:29
  • @Surt I want the constructor to only accept a std::vector<T> argument, not any type that can be converted to std::vector<T>. My goal is for the code to behave like defining two constructors: Vector(const std::vector<T>&) and Vector(std::vector<T>&&), but with just one definition. I want to enforce this strict type match. Commented Oct 28, 2024 at 7:33
  • 2
    I would do MyVector(std::vector<T> data) : data(std::move(data)) {} Commented Oct 28, 2024 at 8:28

1 Answer 1

3

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)) {} 
Sign up to request clarification or add additional context in comments.

4 Comments

It should be MyVector(U) -> ... instead.
@PasserBy Sure? MyVector(U&&) -> worked for me.
U&& would require typename std::decay_t<U>::value_type.
@Jarod42 you are right, moreover std::decay_t is needed in the requires clause. Will fix.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.