9

我想创建一个对对象进行可选引用的函数,如果没有提供,则在函数的持续时间内创建一个函数,即

void Foo(Bar& b = Bar()) { /* stuff */ }

当然,这是无效的代码,因为 aBar不能Bar在此上下文中隐式转换为引用。引用不能是const,因为b在函数内部发生了变异。

您可以通过使用右值引用来解决这个问题,即

void Foo(Bar&& b = Bar()) { /* stuff */ }

这是对右值引用的有效使用吗?调用者现在必须调用std::move他们的Bar参数,即使我无意清除已传递的Bar,就像您传递右值时通常的情况一样。

4

2 回答 2

11
void Foo(Bar&& b = Bar()) { /* stuff */ }

这当然是对 r 值引用的有效使用,但它不以任何方式反映实际语义,因此“被设计破坏”。

您想要做的是使用提供默认参数的转发器函数,如下所示:

void Foo(Bar& b) { /* stuff */ }
void Foo() { Bar b{}; Foo(b); }

或者使用静态默认参数(注意这总是重用同一个对象):

template<class T> decltype(T{})& default_object() {static T x{}; return x;}
void Foo(Bar& b = default_object<Bar>()) { /* stuff */ }

或者像 KerrekSB 在评论中建议(我添加constexpr)使用这个危险的模板函数:

template<class T> constexpr T& no_move(T&& t) { return t; }
void Foo(Bar& b = no_move(Bar{})) { /* stuff */ }
于 2014-08-11T22:05:22.747 回答
8

所以你有一个函数,它接受一个输入输出参数,它将修改它以将信息传回给调用者。

但是您希望参数是可选的。

因此,您的解决方案是通过要求调用者移动参数(这通常意味着他们失去了他们拥有的任何状态或可能处于未指定状态)来使参数看起来是一个 in 参数。这是一个糟糕的、糟糕的设计。您会将调用者与为方便函数内部实现而创建的奇怪 API 混淆。您应该为用户而不是实现者设计 API。

您可以按照 Deduplicator 的建议进行操作,并将其拆分为两个函数,一个提供一个虚拟对象作为输入输出参数,然后将其丢弃:

void Foo(Bar& b) { /* stuff */ }
void Foo() { Bar dummy{}; Foo(dummy); }

或者由于您似乎想要的是可以为空的引用,请停止使用引用并使用正确的语言功能来通过引用传递可以为空的内容:

void Foo(Bar* b) { /* stuff, updating b if not null */ }
于 2014-08-11T22:36:11.043 回答