-
30-09-2019 - |
题
我看过很多介绍可变参数模板的链接。但我从未见过任何可编译的示例来演示这种方法。
有人可以给我提供一些可以找到此类可编译示例的链接吗?
解决方案
Variadic模板是尚未正式发布的C ++ 0x标准的一部分。它们自第4.3版以来得到GCC的支持,但是您需要通过添加编译器开关-STD = C ++ 0x来启用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";
}
Variadic模板是C ++ 0x功能,主要针对通用库的作者。我不希望在“用户代码”中看到它们。例如,在C ++ 0x标准库中,它们在许多地方使用:std :: function,std :: async,std :: reference_wrapper,std :: tuple,std,std :: packaged_task,...
为了给您一个示例,我将向您展示如何相对于variadic模板实现参考_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功能:
- 删除功能(禁用RVALUE的构造函数)
- RVALUE参考(将RVALUE参数检测到构造函数,完美的转发)
- 通过
decltype
- 标准库功能模板
declval
创建对象以构建表达式的目的decltype
(GCC尚未提供此功能模板。您必须自己写) - variadic模板(接受任意数量的参数)
variadic成员模板的目的是将参数转发给所引用的对象 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;}
很快...
其中任何一个都可以。希望这对您下次编写此类函数或类时有所帮助。
这是我在博客上放置的variadic模板的一个示例:http://thenewcpp.wordpress.com/2011/11/23/variadic-templates-part-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之前,您只能使用固定的参数计数创建模板。
使用一个参数为函数的FIRTS模板。
使用两个参数的函数的第二个模板。 ... 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> >