2017-01-01 48 views
1

我遇到以下情况而重构旧代码:不复制它传递可选对象

// pointers to const are discouraged in our code base 
void Do(Foo* exists, Foo* maybe_null) { 
    // does not change *exists or *maybe_null 
} 

int main() { 
    // ... 
    Do(&foos[i], test_both ? &bars[i] : nullptr); 
    // ... 
    HighOrderFunction(foos, bars, &Do); 
    // ... 
} 

所以,Do被称为与的,而第二个可能不会,这取决于一些外界一个肯定存在2个Foo对象测试。我正在尝试解决以下当前代码的问题:

  • 第一个参数永远不会为空,因此它的指针属性从不使用。

  • 我一般不喜欢使用null作为空值。

到目前为止,我想出了三种可能的解决方案,没有一个我完全满意,其中:

  • Do(const Foo&, Foo*):第二个参数有相同的问题,因为以前和现在的呼叫语法不再统一(foos[i]&bars[i]),这可能会混淆读者。

  • Do(const Foo&, const optional<Foo>&):第二个Foo对象必须被复制来构造可选项。

  • Do(const Foo&, optional<const Foo&>):由于不允许可选的引用类型,因此实际上并不工作。

  • Do(const Foo&)Do(const Foo&, const Foo&)过载:当我需要通过做一个函数指针

那么,有没有更好/更清洁的解决方案,我可以在这种情况下使用造成的问题?

(我用C一些性病增加像可选++ 11)

+3

为'void Do(const Foo&)'和'void Do(const Foo&,const Foo&)'重载? – Unimportant

+2

'test_both'是运行时值还是编译时值? – skypjack

+0

@重要感谢您的评论。我忘了提及一个指向Do的指针需要不时地传递给更高阶的函数,所以过载不是一个选项。对于混淆抱歉,我将这些信息添加到了我的问题中。 –

回答

2

Do算符,而不仅仅是一个功能。

struct Do 
{ 
     void operator()(const Foo &must_be_provided); 
     void operator()(const Foo &must_be_provided, const Foo &maybe_unneeded); 
}; 

,然后,实施这两种形式的Do::operator()

void some_function(Do f) 
{ 
     // assume access to foos and bars here 
    if (test_both) // assume determined at run time 
     f(foos[i]); 
    else 
     f(foos[i], bars[i]); 
} 

注意,一个算符可通过数值来传递,通过引用,或它的地址可以在一个指针被传递后(虽然调用函数的语法稍微改变)。

2

如果你想要一个可选的参考,您可以使用std::reference_wrapper<Foo>

Do(const Foo&, optional<std::reference_wrapper<const Foo>>) 

这将避免复制你的对象。并会使功能正式接受参考。

确定有一个reference_wrapper对象已创建。但它相当轻。大多数实现只是屏蔽指针。

+0

谢谢,这可能是我的想法使用可选的最佳执行。我仍然将其他答案标记为接受,因为它为我所遇到的一般问题提供了一个更清晰的解决方案。 –