我发现有时函数有很多参数。这些参数中有很多都是可选的,有时这些选项中的一组通常来自一个其他对象(所以你最终会做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));
}
答案 0 :(得分:1)
答案 1 :(得分:0)
我认为这通常称为 opaque typedef 或 strong typedef 。我们的想法是解决您正在描述的确切问题 - 您的类型具有整数值,但您希望能够明确设置它们。
有关此概念的更多动机,您可以看到this proposal包含在语言和Boost's implementation中。