Search code examples
c++variadic-templatesvariadic-functionsc++-concepts

Bind both lvalues and rvalues to variadic class template parameter


I have a class template that take a variadic number of template arguments. The class has some functions that take arguments corresponding to the class's template parameters. I would like these functions to bind to both lvalues and rvalues. How can I achieve this?

template<class ...C>
class Graph {
public:
    Graph(C &...Context); // <- Only lvalues
    Graph(C &&...Context); // <- Only rvalues
    Graph(auto &&...Context); // <- Both lvalues and rvalues, but does not enforce that the types correspond to ...C
};

It doesn't seem to be possible to create a concept inside the class. Can I create a concept outside the class and pass both the class template pack and the function template pack and verify them in some way? Or can I can add a requires clause to the function that can solve it?

I have found some similar questions, but they are quite old, so there are no answers using concepts.


Solution

  • It sounds like what you want is

    template<class... C>
    class Graph {
    public:
        template<class... Ts>
        requires (std::same_as<Ts&, C&> and ...)
        Graph(Ts&&... Context);
    };
    

    This exploits reference collapsing rules for concision.

    If you want, you can write a concept for this (here written out in full):

    template<class T, class U>
    concept same_as_or_lvalue_reference_to = std::same_as<T, U> or std::same_as<T, U&>;
    
    template<class... C>
    class Graph {
    public:
        Graph(same_as_or_lvalue_reference_to<C> auto&&... Context);
    };