此方法是否已经有名称

Does this method already have a name?

本文关键字:有名称 是否 此方法      更新时间:2023-10-16

我发现有时候函数有很多参数。这些参数中的许多都是可选的,有时这些选项中的一组通常来自单个其他对象(所以您最终会做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对它的实现。