当函数有很多参数和客户端代码只需更改其中时,如何处理情况就可以处理

how to deal with situation when function has lot of params and client code needs only change only few of them?

本文关键字:处理 何处理 就可以 情况 参数 函数 客户端 代码      更新时间:2023-10-16

在这种情况下如何不迷失?例如,这是一个返回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);

因此,任何读取代码的人都知道该代码发生了什么(参数的名称很长,但有意义),此外默认参数?

有一个中等著名的习语:命名参数成语。

这个想法很简单:

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));

请查看boost.parameter库。

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

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

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

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

或者,如果可能的话,甚至更好,可以直接更改功能签名,而无需包装器接受汇总配置。

使用可以使用boost::bind(在C 03)或std::bind(在C 11上)重新排序并将某些参数修复到您的函数。

如果您有一些参数仅成对有意义,请使用超载函数。

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

// 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);