rub*_*nvb 43 c++ variadic-templates c++11
我想要做
template<typename... ArgTypes> void print(ArgTypes... Args)
{
print(Args)...;
}
Run Code Online (Sandbox Code Playgroud)
并且它相当于这个相当庞大的递归链:
template<typename T, typename... ArgTypes> void print(const T& t, ArgTypes... Args)
{
print(t);
print(Args...);
}
Run Code Online (Sandbox Code Playgroud)
然后是我想要打印的每种类型的显式单参数专精.
递归实现的"问题"是生成了大量冗余代码,因为每个递归步骤都会产生一个新的N-1
参数函数,而我想要的代码只会为单个N
-arg print
函数生成代码,并且具有最多的N
专业print
功能.
R. *_*des 69
C++ 17倍表达式
(f(args), ...);
Run Code Online (Sandbox Code Playgroud)
如果你调用的东西可能会返回一个带有重载的逗号运算符的对象:
((void)f(args), ...);
Run Code Online (Sandbox Code Playgroud)
Pre-C++ 17解决方案
这里的典型方法是使用哑列表初始化器并在其中进行扩展:
{ print(Args)... }
Run Code Online (Sandbox Code Playgroud)
在卷曲初始化程序中,评估顺序从左到右保证.
但是print
回报void
所以我们需要解决这个问题.让我们把它变成一个int.
{ (print(Args), 0)... }
Run Code Online (Sandbox Code Playgroud)
但是,这不会直接作为声明.我们需要给它一个类型.
using expand_type = int[];
expand_type{ (print(Args), 0)... };
Run Code Online (Sandbox Code Playgroud)
只要Args
包中总有一个元素,这就可以工作.零大小的数组无效,但我们可以通过使它始终至少有一个元素来解决这个问题.
expand_type{ 0, (print(Args), 0)... };
Run Code Online (Sandbox Code Playgroud)
我们可以使用宏来重复使用此模式.
namespace so {
using expand_type = int[];
}
#define SO_EXPAND_SIDE_EFFECTS(PATTERN) ::so::expand_type{ 0, ((PATTERN), 0)... }
// usage
SO_EXPAND_SIDE_EFFECTS(print(Args));
Run Code Online (Sandbox Code Playgroud)
但是,使这种可重用性需要更多关注一些细节.我们不希望在这里使用重载的逗号运算符.逗号不能用其中一个参数重载void
,所以让我们利用它.
#define SO_EXPAND_SIDE_EFFECTS(PATTERN) \
::so::expand_type{ 0, ((PATTERN), void(), 0)... }
Run Code Online (Sandbox Code Playgroud)
如果你是偏执狂害怕编译器分配大量零的零,你可以使用其他类型的列表初始化,但不存储任何东西.
namespace so {
struct expand_type {
template <typename... T>
expand_type(T&&...) {}
};
}
Run Code Online (Sandbox Code Playgroud)
Ben*_*uch 15
C++ 17倍表达式:
(f(args), ...);
Run Code Online (Sandbox Code Playgroud)
保持简单的事情简单;-)
如果你调用的东西可能会返回一个带有重载的逗号运算符的对象:
((void)f(args), ...);
Run Code Online (Sandbox Code Playgroud)
您可以使用更简单易读的方法
template<typename... ArgTypes> void print(ArgTypes... Args)
{
for (const auto& arg : {Args...})
{
print(arg);
}
}
Run Code Online (Sandbox Code Playgroud)
我在编译浏览器中使用了两种变体,并且使用O3或O2的gcc和clang产生完全相同的代码,但我的变体显然更清晰.