Search code examples
c++overloadingc++20forwarding-reference

Using universal references with non template types?


I am building a simple piping operator for vectors, which the user would use like this (pseudocode):

auto x = std::vector{1,2,3} | push_back(10)
                            | push_back(100)
                            ;

Now I tried defining the piping operator like so:

template <typename T>
constexpr inline auto& operator| (std::vector<T>&& vec, std::invocable<std::vector<T>> auto&& func);

But now vec only to r-values (because the type of vec itself is not deduced) ! But I want it to bind to l-values too. How can I do it?

One ugly but functional solution would be to make another overload for my piping operator but with std::vector<int>&. However this is not scalable, ( 2 ^ n overloads for n arguments!), and I believe this is the very reason universal references were created.

How can I use universal references in this case?


Solution

  • Sure, you can use forwarding references.

    template <typename T> inline constexpr bool is_vector = false;
    template <typename ...P> inline constexpr bool is_vector<std::vector<P...>> = true;
    
    template <typename T> requires is_vector<std::remove_cvref_t<T>>
    constexpr auto &operator|(T &&vec, std::invocable<T> auto &&func);
    

    Also, remember that operators should normally be created in the same namespace as one of their parameters, so that ADL can find them. But you can't touch namespace std...

    Also, I don't like the idea of overloading an operator with neither parameter being a class that you created. Unless your users must explicitly opt-in for those operators by doing using namespace ...;.