我发现有时函数有很多参数.这些参数中的很多都是可选的,有时这些选项中的一组通常来自一个其他对象(所以你最终做了foo(Object.GetN(),Object.GetM(),Object.GetK())) .处理它的常用方法是为可能被调用的不同情况创建不同的重载:
foo(int n, int m, int k /*, and on and on*/);
foo(bool b, int m/*, ...*/);
foo(int m, int k/*, ...*/);
foo(Object_t object/*, ...*/);
//...
这里的问题是哪个参数不是特别直观,当你调用不同于你想要的重载时,你会得到相当惊喜.
最近我有一个想法是让它更容易让函数调用正确,并在处理具有许多不同被调用方式的函数时让自己更轻松.这个解决方案并没有涵盖所有可能的必要性,但它对我来说效果很好.
我不是为所有东西创建不同的重载,而是创建1个函数,它只需要一个可变数量的参数,然后提取可能的参数以便在函数内部使用.至于参数,我会将它们包装在为这些函数创建的辅助类中.这将允许用户声明每个整数或布尔或字符串或者你有什么意思而不是依赖于函数签名中的位置信息.
你可以调用foo(OptN(n),OptM(m))来完全清楚每个参数的用途,而不是foo(n,m)(用上面变量的名称表示可能的错误)因为错误解释参数要困难得多.
如果有人对1的可能实施感兴趣,我会在最后加入MCVE.
我以前从未见过或听说过这种技术,但我也很难相信我是第一个想到它的人.所以,最后,我的问题是这个技术已经有了一个名字吗?
如果它还没有名称,我一直在调用这些函数的’声明函数’,因为你声明了每个参数明确表示的内容而不是’位置函数’,它依赖于参数出现的位置来赋予它意义.
MCVE:
#include <iostream>
#include <utility>
struct Option1
{
Option1(bool b):b(b){}
bool b;
bool operator()() const {return b;}
};
struct Option2
{
Option2(int n):n(n){}
int n;
int operator()() const {return n;}
};
struct Group : Option1, Option2
{
Group(bool b, int n):Option1(b), Option2(n){}
};
/*
* Get the option from what the user gave us.
*/
template <class OptionType, class OptionsGetter, class RType>
auto GetOptionImpl(const OptionsGetter & options_getter,
const RType&, std::true_type) ->
decltype(((const OptionType&)options_getter)())
{
return ((const OptionType&)options_getter)();
}
/*
* Get the default value specified since the user didn't pass
* in that option
*/
template <class OptionType, class OptionsGetter, class RType>
RType GetOptionImpl(const OptionsGetter&, const RType & d, std::false_type)
{
return d;
}
/**
* Returns the value of the option OptionType if the user
* passed that in (inside OptionsGetter) and returns the
* default value if they didn't pass it in.
*/
template <class OptionType, class OptionsGetter, class RType>
auto GetOption(const OptionsGetter & oOptionsGetter,
const RType & oDefault) ->
decltype(std::declval<OptionType>()())
{
return GetOptionImpl<OptionType>(oOptionsGetter, oDefault,
std::is_base_of<OptionType, OptionsGetter>());
}
template <class ... Params>
void foo(Params ... params)
{
struct ParamsGetter : Params...
{
ParamsGetter(Params ... p): Params(p)...{}
} params_getter(params...);
if(GetOption<Option1>(params_getter, false))
std::cout << "Option 1 was true ";
else
std::cout << "Option 1 was false ";
std::cout << "Option 2: " << GetOption<Option2>(params_getter, 3) << '\n';
}
int main()
{
foo(Option1{true}, Option2{22});
foo();
foo(Option2{1});
foo(Group(true, 2));
}
输出:
Option 1 was true Option 2: 22
Option 1 was false Option 2: 3
Option 1 was false Option 2: 1
Option 1 was true Option 2: 2
最佳答案 正如评论中所提到的,这个概念称为命名参数.请参阅
wikipedia的说明,以及例如此
proposal,以C语言介绍它.