C++20中的命名参数

2020-09-08 00:13:01

当用户可以调用按名称提供参数的函数时,编程语言支持命名参数,如下面的假设示例(使用C++语法)所示:

Void f(int x,int y);int main(){f(x=1,y=2);}。

C++显然不是这样的语言,已经有很多建议来纠正这一疏漏,但不幸的是,没有一项建议成功。最新的尝试是Axel Naumann的论文“自解释函数参数”(Self-解释性function Arguments),它试图通过只允许用参数名标记普通函数调用来从另一个角度解决这个问题,如。

允许编译器在名称不匹配时发出有用的警告,但不允许省略或重新排序参数。

即使在这种有限的形式下,命名参数仍然非常有用,但这不是这篇文章的主题。这篇文章的内容是,我们已经可以通过使用C99中称为指定初始化程序的功能来实现与C++20中的命名参数非常接近的东西。

结构A{int x;int y;};Aa1={.x=1,.y=2};Aa2={.x=3};//a2.y==0A A3={.y=4};//a3.x==0A A4={.y=5,.x=6};//有效C,无效C++(重排序)。

C++引入了C没有的限制:初始化式必须遵循声明顺序,类似于类成员化式是如何按照成员声明顺序执行的。但在Exchange中,它允许我们提供默认值:

结构A{int x=0;int y=0;};A a3={.y=4};//a3.x==0,无警告

这可以在GCC和Clang下工作,即使没有-std=c++20,因为它们支持早期语言模式中的指定初始值设定项作为扩展,并且它可以在MSVC-std:C++最新版本下工作。

对于更实际的示例,请考虑取自realcode的以下代码片段,它在Boost.Beast websocket上设置10秒超时:

#Include<;boost/beast/websocket/stream.hpp>;#include<;boost/beast/core/tcp_stream.hpp>;#include<;chrono>;void f1(boost::beast::websocket::stream<;boost::beast::tcp_stream>;&;ws){AUTO OPT=boost::beast::websocket::stream_base::timeout();opt.Keep_Alive_Pings=TRUE;OPT.IDLE_TIMEOUT=std::chrono::Second(10);Ws.set_option(Opt);}。

下面是我们如何通过使用上面的成语和<;chrono>;字面来重新表述它:

#使用命名空间std::<;boost/beast/websocket/stream.hpp>;#include<;boost/beast/core/tcp_stream.hpp>;#include_extals;void f2(boost::beast::websocket::stream<;boost::beast::tcp_stream>;&;ws){ws.set_Option({.IDLE_TIMEOUT=10s,.Keep_Alive_pings=TRUE});}包含计时<;计时&>。

除了略显笨拙的({...})语法和需要遵守正确的参数顺序之外,这与理想的情况相差不远;而且它比F1要好得多。

这也适用于构造函数。考虑这个假设的向量类,它类似于std::Vector,不同之处在于它的各种构造函数重载被一个带有命名参数的构造函数重载所替换:

模板<;class T,class A=std::allocator<;t>;>;类向量{private::struct params{std::size_t size=0;T element{};std::size_t acity=0;A分配器{};};public:显式向量(Params P);};

Auto f(){Vector<;int>;v{{.size=4,.element=11,.acity=64}};return v;}