可变参数模板中更好的包扩展语法?
Better pack expansion syntax in variadic template?
谈论已经一成不变的语言语法可能效率不高。
但是,我想看看为什么 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.
但事实并非如此。
为什么不呢?
说服委员会阻止其编译是否存在任何潜在风险?
在此先感谢您。
在您的每一种情况下,您的 "preferred" 符号都会执行与您想要的不同 扩展。它们不是无效的。
如果 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 > >
事实是,这些都是有用的操作。
关键是 ...
对潜在扩展的子 "expressions" 进行操作,而不是直接对包进行操作。
除非您提出的符号可以产生这两个结果,否则它是一个较弱的符号。
Foo(Args)...
和 Foo(Args...)
也是如此。它们不是表达某事的替代方式——它们是在当前 C++ 中表达两种不同事物的方式。您的计划导致第 2 表示第 1,这意味着在您的 C++ 版本中不再有表达第 2 表示的方法。
每个扩展包有两个部分。第一个是什么包正在扩展,第二个是什么"expression"正在扩展。在当前的 C++ 中,被扩展的包都是表达式中未扩展的包:它们没有另外标记。
在您的版本中,您将包标记为要扩展,而从不将表达式标记为要扩展。如果语言能读懂你的想法,它可以找出表达式的位置,但读懂你想法的编程语言通常不是一个好主意。
"mark the expression, not the pack" 的一个副作用是您可以做一些非常强大的事情,比如在主体内的表达式中包含包含未扩展包的整个 lambda,然后生成一组 lambda。在您的系统中表达这一点将具有挑战性。
谈论已经一成不变的语言语法可能效率不高。
但是,我想看看为什么 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.
但事实并非如此。
为什么不呢? 说服委员会阻止其编译是否存在任何潜在风险?
在此先感谢您。
在您的每一种情况下,您的 "preferred" 符号都会执行与您想要的不同 扩展。它们不是无效的。
如果 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 > >
事实是,这些都是有用的操作。
关键是 ...
对潜在扩展的子 "expressions" 进行操作,而不是直接对包进行操作。
除非您提出的符号可以产生这两个结果,否则它是一个较弱的符号。
Foo(Args)...
和 Foo(Args...)
也是如此。它们不是表达某事的替代方式——它们是在当前 C++ 中表达两种不同事物的方式。您的计划导致第 2 表示第 1,这意味着在您的 C++ 版本中不再有表达第 2 表示的方法。
每个扩展包有两个部分。第一个是什么包正在扩展,第二个是什么"expression"正在扩展。在当前的 C++ 中,被扩展的包都是表达式中未扩展的包:它们没有另外标记。
在您的版本中,您将包标记为要扩展,而从不将表达式标记为要扩展。如果语言能读懂你的想法,它可以找出表达式的位置,但读懂你想法的编程语言通常不是一个好主意。
"mark the expression, not the pack" 的一个副作用是您可以做一些非常强大的事情,比如在主体内的表达式中包含包含未扩展包的整个 lambda,然后生成一组 lambda。在您的系统中表达这一点将具有挑战性。