Нетипичные шаблоны переменных функций в C ++ 11 - PullRequest
24 голосов
/ 24 октября 2011

Я видел сообщение в блоге , в котором использовались нетипичные переменные шаблоны (в настоящее время не поддерживается gcc, только clang).

template <class T, size_t... Dimensions>
struct MultiDimArray { /* ... */ };

Пример в сообщении компилируется нормально, ноМне не удалось заставить его работать с шаблонами функций.

Может кто-нибудь помочь выяснить правильный синтаксис (если таковой существует)?

int max(int n) { return n; } // end condition

template <int... N> // replacing int... with typename... works
int max(int n, N... rest) // !! error: unknown type name 'N'
{
    int tmp = max(rest...);
    return n < tmp? tmp : n;
}

#include <iostream>
int main() 
{
   std::cout << max(3, 1, 4, 2, 5, 0) << std::endl;   
}

Ответы [ 5 ]

13 голосов
/ 24 октября 2011

Вы просто путаете имена типов и имена не типов.То, что вы хотите, просто не работает.

Вы можете , вероятно, использовать переменные нетипичные шаблоны в функциях, но не в качестве (не шаблонных) аргументов:

template <int N, int... Rest>
int max()
{
    int tmp = max<Rest...>();
    return N < tmp ? tmp : N;
}
std::cout << max<3, 1, 4, 2, 5, 0>() << std::endl;

… хотя я не проверял это, и я не уверен, как это должно работать, учитывая, что вам нужно иметь частичную специализацию в качестве базового варианта.Вы можете решить эту проблему, отправив частично специализированную структуру:

template <int N, int... Rest>
struct max_t {
    static int const value = max_t<Rest...>::value > N ? max_t<Rest...>::value : N;
};

template <int N>
struct max_t<N> {
    static int const value = N;
};


template <int... NS>
int max()
{
    return max_t<NS...>::value;
}

Это будет работать.

10 голосов
/ 15 декабря 2012

Это распечатает все элементы, получить максимум может быть реализовано аналогично

template <int N>
void foo(){
  cout << N << endl;
}

template <int N, int M, int ... Rest>
void foo(){
  cout << N << endl;
  foo<M, Rest...>();
}


int main(){
  foo<1, 5, 7>();

  return 0;
}
7 голосов
/ 24 октября 2011

Вот два способа определения шаблона функции переменной, принимающего только параметры int.Первый генерирует серьезную ошибку при создании экземпляра, второй использует SFINAE:

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

template<typename First, typename... Rest>
struct and_
: std::integral_constant<
    bool
    , First::value && and_<Rest...>::value
> {};

template<typename... T>
void
foo(T... t)
{
    static_assert(
        and_<std::is_same<T, int>...>::value
        , "Invalid parameter was passed" );
    // ...
}

template<
    typename... T
    , typename = typename std::enable_if<
        and_<std::is_same<T, int>...>::value
    >::type
>
void
foo(T... t)
{
    // ...
}

Как видите, здесь нетипичные параметры шаблона.

1 голос
/ 11 июля 2015

Вот как вы можете получить переменные аргументы в вашем примере max, так что он может принимать любое количество арифметических аргументов:

template<typename T, typename ... Ts>
struct are_arithmetic{
    enum {
        value = std::is_arithmetic<T>::value && are_arithmetic<Ts...>::value
    };
};

template<typename T>
struct are_arithmetic<T>{
    enum {
        value = std::is_arithmetic<T>::value
    };
};

template<typename Arg, typename = typename std::enable_if<std::is_arithmetic<Arg>::value>::type>
Arg max(Arg arg){
    return arg;
}

template<typename Arg, typename Arg1, typename ... Args, typename = typename std::enable_if<are_arithmetic<Arg, Arg1, Args...>::value>::type>
auto max(Arg arg, Arg1 arg1, Args ... args){
    auto max_rest = max(arg1, args...);
    return arg > max_rest ? arg : max_rest;
}

int main(){
    auto res = max(1.0, 2, 3.0f, 5, 7l);
}

Это хорошо, потому что он может принимать любой числовой тип и будет возвращатьмаксимальное число по исходному типу, а не просто int тоже.

1 голос
/ 13 ноября 2011

Решение Люка Дантона не работает правильно с параметрами, которые не относятся к типу int, но могут быть неявно преобразованы в int.Вот тот, который делает:

template<typename T, typename U> struct first_type { typedef T type; };
template<typename T> int max_checked(T n) { return n; }
template<typename T1, typename T2, typename ...Ts>
int max_checked(T1 n1, T2 n2, Ts ...ns)
{
  int maxRest = max_checked(n2, ns...);
  return n1 > maxRest ? n1 : maxRest;
}
template<typename ...T> auto max(T &&...t) ->
  decltype(max_checked<typename first_type<int, T>::type...>(t...))
{
  return max_checked<typename first_type<int, T>::type...>(t...);
}

struct S { operator int() { return 3; } };
int v = max(1, 2.0, S()); // v = 3.

Здесь max пересылает все неизмененные аргументы в max_checked, который принимает то же количество аргументов типа int (предоставленное путем выполнения расширения пакета дляfirst_type шаблон).Возвращаемый тип decltype(...) используется для применения SFINAE, если какой-либо аргумент не может быть преобразован в int.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...