我看过很多介绍可变参数模板的链接。但我从未见过任何演示这种方法的可编译示例。
有人可以为我提供一些可以找到此类可编译示例的链接吗?
我看过很多介绍可变参数模板的链接。但我从未见过任何演示这种方法的可编译示例。
有人可以为我提供一些可以找到此类可编译示例的链接吗?
最简单的示例之一是以下实现,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::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
如果您仔细遵循了Point#3,您一定已经意识到print(T t, Args... args)
无法处理Level 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-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++0x 标准的一部分。gcc 从 4.3 版开始支持它们,但您需要通过添加编译器开关 -std=c++0x 来启用对 C++0x 的支持。
在 C++11 之前,您只能使用固定数量的参数创建模板。
带有一个参数的函数的第一个模板。
具有两个参数的函数的第二个模板。... IE
由于 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> >