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