lizarisk lizarisk - 1 month ago 7
C++ Question

Nested template parameters and cv- and ref- qualifiers for function arguments

I have a function which looks somewhat like this:

template <typename... A, typename... B>
void foo(Foo<A...>&, Foo<B...>&);


The problem is, I want it to accept any types of references (lvalue/rvalue) in both const/non-const versions for both arguments.

That's already 16 combinations, and obviously it's too many to write them manually.

The only solution I could see is to drop the nested type parameters:

template <typename X, typename Y>
void foo(X&&, Y&&);
// + some SFINAE to enforce that X, Y are Foo-s


This is not acceptable, because I do need to know these nested types
A...
and
B...
. What should I do?

Answer

You can accept arguments by taking forwarding-references and pass their types separately, wrapped in a helper type, tag.

#include <type_traits>
#include <utility>

template <typename> struct tag {};

template <typename X, typename Y, typename... A, typename... B>
void foo(X&& x, Y&& y, tag<Foo<A...>>, tag<Foo<B...>>)
{
    // handle x and y
}

template <typename X, typename Y>
void foo(X&& x, Y&& y)
{
    return foo(std::forward<X>(x), std::forward<Y>(y)
             , tag<typename std::decay<X>::type>{}
             , tag<typename std::decay<Y>::type>{});
}

DEMO