Mat*_*ine 6 c++ pass-by-reference rvalue-reference move-semantics default-arguments
我想创建一个函数,它接受一个对象的可选引用,如果没有提供,则在函数的持续时间内创建一个函数,即
void Foo(Bar& b = Bar()) { /* stuff */ }
Run Code Online (Sandbox Code Playgroud)
当然,这是无效代码,因为在此上下文中Bar无法隐式转换为Bar引用.引用不能const,就像b函数内部的变异一样.
你可以通过使用右值参考来解决这个问题,即
void Foo(Bar&& b = Bar()) { /* stuff */ }
Run Code Online (Sandbox Code Playgroud)
这是rvalue引用的有效用法吗?调用者现在必须调用std::move他们的Bar参数,即使我无意清除传递Bar,通常是在传递rvalues时的情况.
Ded*_*tor 10
void Foo(Bar&& b = Bar()) { /* stuff */ }
Run Code Online (Sandbox Code Playgroud)
这当然是对r值引用的有效使用,但它不以任何方式反映实际的语义,因此"被设计破坏".
你想要做的是使用转发器函数提供默认参数,如下所示:
void Foo(Bar& b) { /* stuff */ }
void Foo() { Bar b{}; Foo(b); }
Run Code Online (Sandbox Code Playgroud)
或者使用静态default-argument(注意这总是重用同一个对象):
template<class T> decltype(T{})& default_object() {static T x{}; return x;}
void Foo(Bar& b = default_object<Bar>()) { /* stuff */ }
Run Code Online (Sandbox Code Playgroud)
或者像KerrekSB在评论中提出的(我添加constexpr)使用这个危险的模板函数:
template<class T> constexpr T& no_move(T&& t) { return t; }
void Foo(Bar& b = no_move(Bar{})) { /* stuff */ }
Run Code Online (Sandbox Code Playgroud)
因此,您有一个函数,它接受一个要修改的输入输出参数,以便将信息传递给调用者.
但是您希望参数是可选的.
因此,您的解决方案是通过要求调用者移动参数(这通常意味着他们丢失了他们拥有的状态或可能处于未指定状态)来使参数看起来像是in参数.这是一个糟糕的,糟糕的设计.您将使用为了方便函数内部实现而创建的奇怪API混淆调用者.您应该为用户而不是实现者设计API.
您可以执行Deduplicator建议并将其拆分为两个函数,一个提供虚拟对象作为输入输出参数然后丢弃:
void Foo(Bar& b) { /* stuff */ }
void Foo() { Bar dummy{}; Foo(dummy); }
Run Code Online (Sandbox Code Playgroud)
或者,因为你似乎想要的是一个可以为null的引用,停止使用引用并使用正确的语言功能通过引用传递一些东西,而不是:
void Foo(Bar* b) { /* stuff, updating b if not null */ }
Run Code Online (Sandbox Code Playgroud)