2

在那种情况下如何不迷路?例如,这是一个返回 bool 但接受 10 个参数的函数:

bool myFunc(bool par1 = true, bool par2 = false, bool par3 = true,
  bool par4 = true /* and so on */ ) {}

假设函数参数在 90% 的情况下设置为默认值。但有时客户端代码只想更改其中的几个。我在这里看到的唯一选择是煞费苦心地复制所有默认参数,直到我们找到需要更改的参数。以这种方式调用此函数的任何机会:

bool myVal = myFunc(par10 = true, par20 = false);

因此,任何阅读代码的人都知道代码发生了什么(参数的名称很长但很有意义),而且当我更改函数定义时,每当调用它来更新默认参数时,我都不需要查看?

4

5 回答 5

11

有一个成语比较有名:命名参数成语。

这个想法很简单:

class Parameters {
public:
    Parameters(): _1(true), _2(false), _3(true), _4(true) {}

    bool get1() const { return _1; }
    bool get2() const { return _2; }
    bool get3() const { return _3; }
    bool get4() const { return _4; }

    Parameters& set1(bool t) { _1 = t; return *this; }
    Parameters& set2(bool t) { _2 = t; return *this; }
    Parameters& set3(bool t) { _3 = t; return *this; }
    Parameters& set4(bool t) { _4 = t; return *this; }

private:
    bool _1;
    bool _2;
    bool _3;
    bool _4;
};

bool myFunc(Parameters p);

然后客户端可以这样做:

result = myFunc(Parameters());

或者:

result = myFunc(Parameters().set4(false));
于 2012-12-21T16:38:26.990 回答
2

看看boost.parameter库。

使用此库编写可以按名称接受参数的函数和类模板:

 new_window("alert", _width=10, _titlebar=false);
 smart_ptr<Foo, deleter<Deallocate<Foo> >, copy_policy<DeepCopy> > p(new Foo);

由于命名参数可以按任何顺序传递,因此当函数或模板具有多个具有有用默认值的参数时,它们特别有用。该库还支持推导参数;也就是说,可以从其类型推导出其身份的参数。

于 2012-12-21T16:36:18.070 回答
1

这是应避免使用此类接口的原因之一。为您的 func 创建一个包装器,接受包含所有参数的结构。在客户端实例化默认配置(只要你想调用你的函数就让它可用;例如在对象上下文中)。每当您想调用 func 时,将配置复制到另一个实例,更改您想要的值并将其传递给您包装的 func。

或者,更好的是,如果可能的话,直接更改函数签名而不使用包装器以接受聚合配置。

于 2012-12-21T16:38:00.930 回答
0

使用可以使用boost::bind(在 C++03 上)或std::bind(在 C++11 上)重新排序和修复函数的一些参数。

于 2012-12-21T16:33:09.027 回答
0

如果您遇到某些参数仅成对有意义的情况,请使用重载函数。

所以代替例如(对不起,现在没有更好的例子)

// Adds a new TODO. Either this is a low-prio TODO with no defined 
// deadline, xor a deadlined TODO for which year, month, day must
// be passed.
void add_todo (std::string description, int year=-1, int month=-1, int day=-1);

void add_todo (std::string description, int year, month, day);

void add_todo (std::string description) {
    add_todo(description, -1, -1, -1);
}

因此要强制执行两个可能的调用签名中的一个且仅一个。

当然,最好添加更多结构,例如Date. 但即便如此,我也不建议Date仅仅为了它而使“可空”:

void add_todo (std::string description, Date = Date::None); // <-- I wouldn't

反而

void add_todo (std::string description);
void add_todo (std::string description, Date deadline);

或者有时没有过载,也没有默认值

void add_todo (std::string description);
void add_deadlined_todo (std::string description, Date deadline);
于 2012-12-21T16:49:03.230 回答