谈论已经一成不变的语言语法可能效率不高。
但是,我想知道为什么C++11 variadic template's argument expansion
在某些嵌套用法方面无法更明确地阅读。
例如,我认为C ++开发人员通常可以更清楚地编写如下代码。 (如果允许的话)
template<typename ...> struct Tuple
{
};
template<typename T1, typename T2> struct Pair
{
};
template<class ...Args1> struct zip
{
template<class ...Args2> struct with
{
typedef Tuple<Pair<Args1, Args2>...> type;
// More code but but maybe better readability?
// because Args1, and Args2 are the ones that get
// actually expanded, not Pair<T1, T2>.
// typedef Tuple<Pair<Args1..., Args2...>> type; // ## Invalid! ##
};
};
typedef zip<short, int>::with<unsigned short, unsigned>::type T1;
通过这样做,我们真的不必混淆哪些模板类型正在被扩展,或者应该是在进行多嵌套variadic template
时必须扩展的模板类型,因为它变得更加重要让你的代码看起来比缩短更清晰。
另外,我喜欢以与调用函数相同的方式查看代码,如下所示:
Foo(args...); // Okay.
我们不这样做:
Foo(args)...; // Error.
修改
我相信这个应该至少被允许工作得很好。
Tuple<Pair<Args1..., Args2...>> // Invalid code.
但事实并非如此。
为什么不呢? 是否存在任何潜在的风险来说服委员会足以阻止其编制?
提前非常感谢你。
答案 0 :(得分:2)
在您的每一个案例中,您的“首选”符号都会与您想要的不同扩展。它们无效。
如果Args0
= {a,b,c
}和Args1
= {int,double,char
},那么:
std::tuple< foo< Args0..., Args1... > >
是
std::tuple< foo< a,b,c,int,double,char > >
,而
std::tuple< foo< Args0, Args1>... >
是
std::tuple< foo< a, int >, foo< b, double >, foo< c, char > >
问题是,这些都是有用的操作。
关键是...
对可能扩展的子“表达式”进行操作,而不是直接对包进行操作。
除非您提出的符号可以产生这两种结果,否则它是一种较弱的符号。
Foo(Args)...
和Foo(Args...)
也是如此。它们不是说话的替代方式 - 它们是在当前C ++中说两种不同的东西的方式。你的计划在第二个意思是第一个,这意味着你不再能够表达你的C ++版本中第二个含义。
每次扩展都有两个部分。第一个是正在扩展哪些包,第二个是正在扩展的“表达式”。在当前的C ++中,正在扩展的包都是表达式中未展开的包:它们没有标记。
在您的版本中,您将包标记为展开,并且从不标记要展开的表达式。如果这种语言能够读懂你的想法,它就可以找出那个表达式的位置,但是阅读你的思维的编程语言通常是一个坏主意。
“标记表达而不是包装”的副作用是你可以做一些非常强大的东西,比如让整个lambda包含在体内的表达式内的未扩展包,然后生成一包lambdas。在你的系统中表达这将是一项挑战。