Вопрос

Я видел много ссылок, представляющих вариативные шаблоны.Но я никогда не видел ни одного компилируемого примера, демонстрирующего этот подход.

Может ли кто-нибудь предоставить мне ссылки, в которых можно найти такие компилируемые примеры?

Это было полезно?

Решение

Вариадические шаблоны являются частью стандарта C ++ 0x, который еще не выпущен официально. Они поддерживаются GCC с версии 4.3, но вам нужно включить поддержку C ++ 0x, добавив компилятор-выключатель -std = C ++ 0x.

Другие советы

Одним из самых простых возможных примеров является следующая реализация max который даже не шаблон на типов.

int maximum(int n)
{
    return n;
}

template<typename... Args>
int maximum(int n, Args... args)
{
    return max(n, maximum(args...));
}

Только чуть более сложный - это каноническое printf реализация:

void printf(const char *s)
{
  while (*s)
  {
    if (*s == '%' && *(++s) != '%')
      throw "invalid format string: missing arguments";
    std::cout << *s++;
  }
}

template<typename T, typename... Args>
void printf(const char* s, T value, Args... args)
{
  while (*s)
  {
    if (*s == '%' && *(++s) != '%')
    {
      std::cout << value;
      printf(s, args...); // call even when *s == 0 to detect extra arguments
      return;
    }
    std::cout << *s++;
  }
  throw "extra arguments provided to printf";
}

Вариадические шаблоны представляют собой функцию C ++ 0x, которая в основном предназначена для авторов общих библиотек. Я не ожидаю увидеть их в «пользовательском коде». Например, в стандартной библиотеке C ++ 0x они используются во многих местах: STD :: Функция, std :: async, std :: Справочник_wrapper, std :: tupple, std :: packaged_task, ...

Чтобы привести пример, я покажу вам, как будет реализован справочник в отношении вариационных шаблонов:

template<class T>
class reference_wrapper
{
    T *ptr;
public:
    explicit reference_wrapper(T& thing) : ptr(&thing) {}
    explicit reference_wrapper(T&&     ) = delete;

    operator T&() const {return *ptr;}

    template<class... Args>
    decltype( declval<T&>()(declval<Args>()...) )
    operator()(Args&&... args) const
    {
        return (*ptr)(forward<Args>(args)...);
    }
};

Это не совсем соответствует стандартному проекту, но он должен быть коммутилируется с небольшой модификацией. Это демонстрирует несколько функций C ++ 0x:

  • Удаленные функции (отключение конструктора для RValues)
  • RVALUE Список ссылок (обнаружение аргументов RValue конструктору, идеальная экспедиция)
  • Тип вычета через decltype
  • Стандартный шаблон функции библиотеки declval создавать объекты с целью построения выражения для decltype (GCC еще не предлагает этот шаблон функции. Вы должны написать это самостоятельно)
  • Вариадические шаблоны (принимающие произвольное количество параметров)

Назначение шаблона Variadic Member - пересылать аргументы объекту, упомянутому ptr. Отказ Это должно работать в случае, если T является типом указателя функции или тип класса с перегруженным оператором вызова функций.

ваше здоровье! с

Очень простой пример вариативного шаблона:

Предположим, мы хотим иметь функцию, которая принимает переменное количество аргументов и печатает их все.Например:

print("Hello", 1, 3.14, 5L);

Чтобы эта функциональность работала, нам в основном потребуются две функции:

Во-первых, функция, которая принимает переменное количество аргументов:

template<typename T, typename... Args>
void print(T t, Args ...args){
     std::cout << t << ", ";
     print(args...);
}

Некоторые объяснения:

1.) Пакеты параметров, обозначенные многоточием (...), которые появляются в списке параметров.

typename...Args 
        |  | << Optional whitespace. Can have multiple whitespaces in between them
    Args...args

Это означает, что все они одинаковы.

typename ...args
typename...args
typename   ...   args

Таким образом, вам не нужно беспокоиться о правильном положении пробелов.Тем не менее, IMO, рекомендуется использовать не более одного пробела.

2.) Расширение пакета:Шаблон, за которым следует многоточие.

print(args...); //expand when you wish to use them

3.) Пакет параметров принимает ноль или больше аргументы шаблона.Так, print(T t, Args... args) принимает один или больше аргументы.


Как только вы это поймете, мы сможем визуализировать поток вызовов, как показано ниже:

print("Hello", 1, 3.14, 5L);

переводится как:

print(string, int, float, long);

который вызывает

print(int, float, long);

который вызывает

print(float, long);  // say Level 2

который вызывает

print(long);         // say Level 1

который вызывает

print();             // say Level 0

Если вы внимательно следовали пункту №3, вы, должно быть, поняли, что print(T t, Args... args) не может обработать вызов на уровне 0.
Поэтому нам нужна еще одна функция с тем же именем, чтобы догнать ее на любом уровне >=0.


Во-вторых, функция для схватить вызов на вершине стека вызовов:

Поймать на уровне 0:

void print(){}

или «Поймать на уровне 1»:

template<typename T>
void print(T t){ std::cout << t;}

или «Поймать на уровне 2»:

template<typename T, typename U>
void print(T t, U u){ std::cout << t << ", " << u;}

скоро...

Любой из них будет работать.Надеюсь, это поможет вам в следующий раз, когда вы будете писать такую ​​функцию или класс.

Это пример вариадиадических шаблонов, которые я поставил в моем блоге:http://thenewcpp.wordpress.com/2011/11/23/variadic-templates-part-----/

Это компилирует. Он демонстрирует поиск самого большого типа из группы типов.

#include <type_traits>

template <typename... Args>
struct find_biggest;

//the biggest of one thing is that one thing
template <typename First>
struct find_biggest<First>
{
  typedef First type;
};

//the biggest of everything in Args and First
template <typename First, typename... Args>
struct find_biggest<First, Args...>
{
  typedef typename find_biggest<Args...>::type next;
  typedef typename std::conditional
  <
    sizeof(First) >= sizeof(next),
    First,
    next
  >::type type;
};

Перед C ++ 11 вы можете создать шаблон только с фиксированным количеством параметров.

Шаблон огня для функции с одним параметром.

Второй шаблон для функции с двумя параметрами. ... то есть

Поскольку C ++ 11 Вы можете написать только один шаблон, компилятор будет генерировать необходимую функцию.

Хороший примерhttp://eli.thegreeenplace.net/2014/variadic-templates-in-c/

Еще один синтаксис: расширение, например,

template<typename VAL, typename... KEYS>
class MyMaps
{
  typedef std::tuple< std::map<KEYS,VAL>... > Maps;
}

следовательно:

MyMaps<int,int,string>:Maps

сейчас на самом деле:

std::tuple<std::map<int,int>,std::map<string,int> >
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top