如何处理(深层)嵌套函数调用中的默认值?

for*_*818 6 c++ default-value

假设有一个具有默认值的函数:

int foo(int x=42);
Run Code Online (Sandbox Code Playgroud)

如果这是由其他人这样调用:

int bar(int x=42) { return foo(x); }
int moo(int x=42) { return bar(x); }
Run Code Online (Sandbox Code Playgroud)

这当然只是一个人为的例子.但是,我有时情况非常相似.该参数仅从最高级别(moo)传递到最低级别,并且仅在实际使用时才传递.关于这一点的坏处是,当我更改foo为具有不同于42我必须搜索所有调用者的默认值并相应地更改默认值时.

是否有一些模式/成语可以避免这种情况?

我想到的唯一简单的解决方案是

int bar()      { return foo(); }
int bar(int x) { return foo(x); }
Run Code Online (Sandbox Code Playgroud)

但是,由于我有点懒,而且在实际代码中这会导致相当多的代码重复,我想避免这种情况.

Pio*_*ycz 6

我建议在下面选择以下两个选项之一(正如您在其他答案中看到的那样 - 有更多可能的解决方案).

  1. 重载您的功能
  2. 定义常量

因此,选项1如下所示:

int foo(int x=42);
int bar(int x) { return foo(x); }
int moo(int x) { return bar(x); }
int bar() { return foo(); }
int moo() { return bar(); }
Run Code Online (Sandbox Code Playgroud)

而且,选项2会更短一些:

constexpr int FOO_DEFAULT = 42;
int foo(int x=FOO_DEFAULT);
int bar(int x=FOO_DEFAULT) { return foo(x); }
int moo(int x=FOO_DEFAULT) { return bar(x); }
Run Code Online (Sandbox Code Playgroud)

对于具有少量默认值(例如一个默认值)的情况,我使用选项-1,对于具有相当多默认值的情况,我使用选项-2 - 如 foo(int a, int b = 3, std::string c = "wow", float pi = 3.14)


Che*_*Alf 2

实用的通用解决方案包括:

  • 使用Optional_类作为参数,例如boost::optional或 DIY 等效项。

  • 命名默认值(并在包装函数定义中使用该名称)。

  • 重载每个包装函数,如问题中所示。

  • 只需重复包装函数定义中的默认值即可,但这违反了 DRY 原则,不要重复自己


评论 else-threadasdf Tobi 中提出了包装器定义为的情况

int asdf(int x=42,int y=42){ return foo(x)+foo(y);}
Run Code Online (Sandbox Code Playgroud)

使用Optional_类:

auto foo( Optional_<int> x)
    -> int
{ return (x.is_empty()? 42 : x.value()); }

auto asdf( Optional_<int> x = {}, Optional_<int> y = {} )
    -> int
{ return foo( x ) + foo( y ); }
Run Code Online (Sandbox Code Playgroud)

使用指定的默认值:

int const foo_default = 42;

auto foo( int x = foo_default )
    -> int
{ return x; }

auto asdf( int x = foo_default, int y = foo_default )
    -> int
{ return foo( x ) + foo( y ); }
Run Code Online (Sandbox Code Playgroud)

使用重载:

auto foo( int x = 42 )
    -> int
{ return x; }

auto asdf()
    -> int
{ return foo() + foo(); }

auto asdf( int x )
    -> int
{ return foo( x ) + foo(); }

auto asdf( int x, int y )
    -> int
{ return foo( x ) + foo( y ); }
Run Code Online (Sandbox Code Playgroud)

值得注意的是,asdf不能轻松地将其定义为转发其参数的函数模板。而且,这样的模板不能轻易地在单独的翻译单元中定义,并且不能获取其地址。由于这些原因,我没有将这个可能的解决方案包含在项目符号列表中:它非常受限制,不是通用解决方案。