Piping operator in c++ I wrote a simple piping operator in c++. I just wanted to make sure that my code was robust, modern c++ code, and made correct use of perfect forwarding.
Here's the code:
#include &lt;concepts&gt;
#include &lt;type_traits&gt;
#include &lt;utility&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;deque&gt;

//Accept an object on the left hand side and a function on the right
template &lt;typename Any, typename... Args&gt;
inline auto operator| (const Any&amp; obj, std::invocable&lt;Any&gt; auto func){
    // Correct use of perfect forwarding??
    return func(std::forward&lt;const Any&amp;&gt;(obj));
}

//Version for a functor which accepts a reference. Do I need to cover other cases?
template &lt;typename Any, typename... Args&gt;
inline auto operator| (Any&amp; obj, std::invocable&lt;Any&amp;&gt; auto func){
    return func(std::forward&lt;Any&amp;&gt;(obj));
}

And here is how the user uses it:
int main() {
    auto x = std::vector{1 , 2 , 3 , 4 , 5 , 6};
    // Piping example 0
    auto y = 5 | [] (int x) {return x * 2;} 
               | [] (int x) {return x * 3;}
               ;
    
    std::cout &lt;&lt; y &lt;&lt; '\n';
    // Piping example 1
    x | [] (std::vector&lt;int&gt;&amp; vec) -&gt; std::vector&lt;int&gt;&amp; {vec.push_back(7); return vec;};

    std::cout &lt;&lt; x[6];
    return 0;
}

And if you want to clean up the lambda syntax (I don't mind personally) and have a cleaner, neater syntax you can do:
namespace piping {
    template &lt;typename T&gt;
    auto push_back(const T&amp; obj) {
        return [obj] (auto&amp; vec) -&gt; auto&amp; {vec.push_back(obj); return vec;};;
    }
}

/* ... Some code */

int main() {
    auto x = std::vector{1 , 2 , 3 ,4 ,5 , 6};
    // A bit cleaner...
    x | piping::push_back(7);
}

Did I make correct use of modern c++ and perfect forwarding?
Thanks in advance.
That seems a worthwhile objective.  The syntax looks a bit clunky when we have to write lambdas inline like that, but you'll probably develop a library of useful filters (like standard Ranges ones) that look much more natural.
I don't think we've got the use of forwarding references quite right - and you'll be pleased to hear that fixing that should simplify the code a bit.
What we should do is use typename Any&amp;&amp;.  Although that looks like an rvalue-reference, it's actually a forwarding reference because Any is a template parameter.
Any&amp;&amp; allows the template parameter to bind to either lvalue or rvalue, so we just need the one function:
template &lt;typename Any&gt;
auto operator| (Any&amp;&amp; obj, std::invocable&lt;Any&gt; auto&amp;&amp; func) {
    return func(std::forward&lt;Any&gt;(obj));
}

(Note also the auto&amp;&amp; for func, so it can be a mutable functor if we want).

Having written that, I'm not so convinced that I like operator|() to be modifying its argument.  I would prefer a | b to leave a alone, and have to write a |= b when I intend a to be modified in place.

Minor points:

There are headers included but not needed for the template:

#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;deque&gt;



inline is implicit for a template function.
We don't need to spell out the full return type for the &quot;append 7&quot; lambda in the example - -&gt; auto&amp; is easier.