私は、関数に非常に多くのパラメータがあることがあることが分かりました。これらのパラメータの多くはオプションであり、これらのオプションのグループはしばしば単一の他のオブジェクトから来ることがあります(つまり、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(n, m)
の代わりにfoo(OptN(n), OptM(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
なぜすべてが必要なのか分かりません.... – jpo38
これはあなたが探しているものですか? https://en.wikipedia.org/wiki/Named_parameter –
ここで説明した手法を使用してもほぼ同じ結果が得られます。http://stackoverflow.com/questions/40381918/preferred-mechanism-to-attacha-a-型からスカラーへ –