此方法是否已经有名称
Does this method already have a name?
我发现有时候函数有很多参数。这些参数中的许多都是可选的,有时这些选项中的一组通常来自单个其他对象(所以您最终会做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/*, ...*/);
//...
这里的问题是哪个参数不是特别直观,当你调用一个不同于你预期的重载时,你会得到相当大的惊喜。
最近我有一个想法,使它更容易得到正确的函数调用,使我的生活更容易,当处理这些函数有许多不同的方式被调用。这个解决方案并没有涵盖所有可能的需求,但它对我来说非常有效。
我将创建一个函数,它只接受可变数量的参数,然后提取可能的参数在函数内部使用,而不是为所有内容创建不同的重载。至于参数,我将把它们包装在为这些函数创建的helper类中。这将允许用户声明每个整数、布尔值、字符串或你所拥有的东西的含义,而不是依赖于函数签名中的位置信息。
而不是foo(n, m)
(上面的变量名称表明可能存在错误),您可以调用foo(OptN(n), OptM(m))
,这样可以完全清楚每个参数的用途,并且更难让参数被误解。
如果有人对这个可能的实现感兴趣,我将在最后包括一个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上的解释,以及在c++中引入它的建议。
我认为这通常被称为不透明类型pedef或强类型pedef。这个想法是为了解决你所描述的问题——你有整数值的类型,但你想让它能够显式地设置它们。
关于这个概念的更多动机,你可以看到这个包含在语言中的提议和Boost对它的实现。
- "typedef"类型名称是否可以像"struct"定义那样声明指向结构的指针?
- 声明是否有可能逃脱其封闭的名称空间
- 是否有一种方法可以避免标头文件中使用的constexpr函数输入全局范围,而无需额外的名称空间
- 模块名称是否驻留在单独的"name space"中,或者它们可能与例如变量名称发生冲突?
- 为什么 GCC 无法优化,除非返回值有名称?
- 自我分配有用时是否存在情况
- GCC 或 Clang 关于函数参数在其自己的默认参数中的范围内的名称是否正确?
- 多次创建相同的对象名称 C++ 是否好
- 阵列不能两次将相同的名称保存,当要添加新字符串时,程序应检查以查看该名称是否已经存在
- 非 OOP 版本的"财产"是否有名称?
- 如何检查一个名称是否与另一个名称引用相同的符号
- c 依赖性名称:是否需要此类型
- C++:此模式是否有名称,是否可以改进
- 在声明中省略参数名称是否是一种好的做法
- 使用相同的参数名称和成员名称是否有效
- 接口的名称是否可以与其类的名称不同?[C++]
- 在同一进程中使用的两个模块中具有同步对象的通用名称是否安全
- 了解QObject名称是否已更改的最佳方法是什么
- 此方法是否已经有名称
- 哪些右值有名称