默认参数vs std ::可选作为参数vs函数重载

时间:2019-05-31 02:49:06

标签: c++

假设我正在实现一个函数func

  • 我有一个用例,其中将使用两个参数来调用func
  • 我还有另一种用例,其中将仅使用一个参数来调用func,但是在该函数中将使用缺少的第二个参数的默认值。

我可以想到三种实现此功能的方法:

  1. 默认参数
void func(int a, long b = c);

func将被这样调用:

func(a);
func(a, b);
  1. 函数重载
void func(int a);
void func(int a, long b);

func将被这样调用:

func(a);
func(a, b);
  1. 使用Optional作为函数参数
void func(int a, optional<long> b);

func将被这样调用:

func(a, optional<long> ());
func(a, b);

我想知道实现所需功能的最佳方法是什么。欢迎任何建议。

1 个答案:

答案 0 :(得分:2)

考虑此问题时有两个问题要问自己:

  • 可选参数是否具有逻辑默认值?
  • 在提供可选参数时和没有提供可选参数时,函数实现的是否相同?

如果第二个参数具有逻辑默认值,并且该函数不管做什么都执行相同的操作,则默认参数可以正常工作。例如:

std::vector<std::string> split_string(const std::string& str, char sep = ' ');

默认情况下,这会在空格处分割字符串,但是可以使用分隔符来更改它。将其分为两个重载或在此处使用std::optional毫无意义。


如果第二个参数没有逻辑默认值,但是如果没有给出该函数,则该函数在大多数情况下仍然相同,那么std::optional就更有意义了。例如:

void extract(const std::filesystem::path& archive_file,
             const std::filesystem::path& output_dir,
             std::optional<std::regex> exclude_filter = {});

在这里,我们正在从存档文件中提取文件,并将提取的文件写入磁盘,可以选择排除与某些模式匹配的文件。使用或不使用过滤器,函数定义在根本上是相同的;这只是一个额外的区别:

if (exclude_filter && std::regex_match(file, *exclude_filter) continue;

重复定义没有多大意义,因此重载实际上没有任何意义。同时,没有“不匹配任何内容”的正则表达式,因此没有可以应用的逻辑默认过滤器。 std::optional非常适合这里。

请注意,我仍然使用默认参数。将您的std::optional设置为空可以使您的通话更加顺畅。


最后,如果函数实现在one-arg和two-arg版本之间根本不同,则请使用重载。例如:

void hide(window& win) {
    win.set_visible(false);
}

template <typename rep, typename period>
void hide(window& win, const std::chrono::duration<rep, period>& fade_time) {
    auto wait_time = equal_intervals(fade_time, win.opacity());
    while (win.oapcity() > 0) {
        win.set_opacity(win.opacity() - 1);
        std::this_thread::sleep_for(wait_time);
    }
}

在这里,我们正在隐藏一个具有可选淡出时间的窗口。尽管这些函数在逻辑上执行相同的操作,但实现方式却完全不同。具有相同的功能没有多大意义。尽管0是逻辑上的默认淡入时间,但在此处使用默认参数仍然没有意义,因为您最终会遇到一个大的if块:

if (fade_time == 0) {
    // body of the first overload
} else {
    // body of the second overload
}