Метод вариационного шаблона для принятия заданного количества парных чисел?

template <unsigned int N> class myclass
{
public:
    template <typename... Args> void mymethod(Args... args)
    {
       // Do interesting stuff
    } 
};

Я хочу, чтобы mymethod вызывался только с ровно N удвоениями. Это возможно? То есть, скажем, что у меня есть:

myclass <3> x;
x.mymethod(3., 4., 5.); // This works
x.mymethod('q', 1., 7.); // This doesn't work
x.mymethod(1., 2.); // This doesn't work

Как я могу это сделать?

Ответы

Ответ 1

Для ограничения количества аргументов вы можете легко проверить, есть ли sizeof...(Args) == N, но для проверки того, что все аргументы удваиваются, вам нужно построить рекурсивный тип, который проверяет std::is_same для каждого из аргументов.

template<typename...>
struct are_same : std::true_type 
{};

template<typename T>
struct are_same<T> : std::true_type
{};

template<typename T, typename U, typename... Types>
struct are_same<T, U, Types...> :
    std::integral_constant<bool, (std::is_same<T, U>::value && are_same<T, Types...>::value)>
{};

Уведомление are_same сначала объявлено, а затем специализировано.

Затем просто примените ограничение в возвращаемом типе метода с помощью std::enable_if, воспользовавшись SFINAE.

template <unsigned int N> class myclass
{
public:
    template <typename... Args>
    typename std::enable_if<(are_same<double, Args...>::value && sizeof...(Args) == N), void>::type
    /* void */ mymethod(Args... args)
    {
        // Do interesting stuff
    } 
};

Ответ 2

Можно попробовать что-то вроде следующего:

#include <type_traits>

template<class T, class...>
struct all_same : std::true_type
{};

template<class T, class U, class... TT>
struct all_same<T, U, TT...>
    : std::integral_constant<bool, std::is_same<T,U>{} && all_same<T, TT...>{}>
{};


template <unsigned int N> class myclass
{
    public:
    template <typename... Args>
     typename std::enable_if<sizeof...(Args) == N, void >::type mymethod(Args... args)
    {
        static_assert(all_same<double, Args...>{}, 
                      "Not all args as Double");
    }
};

<Demo>