Я видел много ссылок, представляющих вариативные шаблоны. Но я никогда не видел компилируемого примера, демонстрирующего этот подход.
Может ли кто-нибудь предоставить мне ссылки, в которых можно найти такие компилируемые примеры?
Я видел много ссылок, представляющих вариативные шаблоны. Но я никогда не видел компилируемого примера, демонстрирующего этот подход.
Может ли кто-нибудь предоставить мне ссылки, в которых можно найти такие компилируемые примеры?
Шаблоны Variadic являются частью стандарта 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";
}
...
после Args
и args
просто синтаксической солью, или есть также способы использования вариативных параметров без ...
?
- person Stewart; 18.10.2011
...
имеет значение. Рассмотрим две вариативные функции шаблона sum
и product
. Теперь вызовите их из другого вариативного шаблона с параметрами 2,3,4
, значение product(sum(args...))
будет 9, а значение product(sum(args)...)
будет 24.
- person Motti; 27.10.2011
printf(s, args...);
рекурсивный вызов во время выполнения другой функции, скомпилированной с одним аргументом меньше, или компилятор рекурсивно расширяет эту строку до тела printf с одним аргументом меньше?
- person Youda008; 14.12.2014
printf
с одним параметром меньше и добавляет вызов этой функции. Этот вызов функции может быть или не быть встроенным, но это не имеет значения.
- person Motti; 14.12.2014
Вариативные шаблоны - это функция C ++ 0x, которая в первую очередь предназначена для авторов общих библиотек. Не ожидал увидеть их в «пользовательском коде». Например, в стандартной библиотеке C ++ 0x они используются во многих местах: std :: function, std :: async, std :: reference_wrapper, std :: tuple, std :: packaged_task, ...
Чтобы дать вам пример, я покажу вам, как reference_wrapper может быть реализован относительно вариативных шаблонов:
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:
decltype
declval
для создания объектов с целью построения выражения для decltype
(GCC еще не предлагает этот шаблон функции. Вы должны написать его самостоятельно)Целью шаблона вариативного члена является пересылка аргументов объекту, на который ссылается ptr
. Это должно работать, если T является типом указателя функции или типом класса с перегруженным оператором вызова функции.
ваше здоровье! s
Очень простой пример вариативного шаблона:
Предположим, мы хотим иметь функцию, которая принимает переменное количество аргументов и печатает их все. Например:
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;}
so on...
Любой из них подойдет. Надеюсь, это поможет вам в следующий раз, когда вы напишете такую функцию или класс.
Это пример вариативных шаблонов, которые я разместил в своем блоге: http://thenewcpp.wordpress.com/2011/11/23/variadic-templates-part-1-2/
Он компилируется. Он демонстрирует поиск самого большого типа из группы типов.
#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.thegreenplace.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> >