这个方法是否已经有了名字?

时间:2016-11-03 19:58:26

标签: c++

我发现有时函数有很多参数。这些参数中有很多都是可选的,有时这些选项中的一组通常来自一个其他对象(所以你最终会做Error - <type 'exceptions.WindowsError'>: [Error 32] The file is already being used by another process: u'C:\\src\\ckan\\ckan\\resources\\a3d\\19a\\ba-7f3f-42fc- a02e-09f50aae0924~' URL: http://localhost:5000/dataset/new_resource/test1 )。处理它的一种常见方法是为可能被称为的不同情况创建不同的重载:

foo(Object.GetN(), Object.GetM(), Object.GetK())

这里的问题是哪个参数不是特别直观,当你调用不同于你想要的重载时,你会感到非常惊讶。

最近我有一个想法是让它更容易让函数调用正确,并且在处理具有许多不同被调用方式的函数时让自己更轻松。这个解决方案并没有涵盖所有可能的必要性,但对我来说效果很好。

不是为所有东西创建不同的重载,而是创建1个函数,它只需要一个可变数量的参数,然后提取可能的参数以便在函数内使用。至于参数,我会将它们包装在为这些函数创建的辅助类中。这将允许用户声明每个整数或布尔或字符串或者你有什么意思,而不是依赖于函数签名中的位置信息。

而不是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/*, ...*/); //... (根据上面变量的名称表示可能存在的错误),您可以调用foo(n, m)来完全清楚每个参数的用途,并且更难以使用有一个参数被误解。

如果有人对1的可能实施感兴趣,我会在最后加入MCVE。

我以前从未见过或听说过这种技术,但我也很难相信我是第一个想到它的人。所以,最后,我的问题是这个技术已经有了一个名字吗?

如果它还没有名字,我一直在调用这些函数的'声明函数',因为你声明了每个参数明确表示的内容而不是'位置函数',它依赖于参数出现的位置来赋予它意义。 / p>

MCVE:

foo(OptN(n), OptM(m))

输出

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

2 个答案:

答案 0 :(得分:1)

如评论中所述,此概念称为命名参数。请参阅wikipedia上的说明,以及此proposal的说明,以便在C ++中介绍它。

答案 1 :(得分:0)

我认为这通常称为 opaque typedef strong typedef 。我们的想法是解决您正在描述的确切问题 - 您的类型具有整数值,但您希望能够明确设置它们。

有关此概念的更多动机,您可以看到this proposal包含在语言和Boost's implementation中。