2016-11-03 21 views
4

私は、関数に非常に多くのパラメータがあることがあることが分かりました。これらのパラメータの多くはオプションであり、これらのオプションのグループはしばしば単一の他のオブジェクトから来ることがあります(つまり、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 
+0

なぜすべてが必要なのか分かりません.... – jpo38

+0

これはあなたが探しているものですか? https://en.wikipedia.org/wiki/Named_pa​​rameter –

+0

ここで説明した手法を使用してもほぼ同じ結果が得られます。http://stackoverflow.com/questions/40381918/preferred-mechanism-to-attacha-a-型からスカラーへ –

答えて

1

コメントで述べたように、この概念は、名前付きパラメータと呼ばれています。 wikipediaの説明、および例えばproposalを参照してC++で紹介してください。

+0

記事を読むと、これはC++のように見えますが、これは_namedパラメータidiom_と呼ばれ、記事ではメソッドを連鎖させて実装する方法について説明しています。私はそれがC++ 11の可変的なテンプレートでは少しばかり古くなっていると思います。 – SirGuy

0

私は、これは一般的に不透明のtypedefまたは強いtypedefをと呼ばれていると思います。この考え方は、記述している正確な問題を解決することです。積分値を持つ型がありますが、明示的に設定できるようにする必要があります。

このコンセプトのモチベーションを高めるために、this proposalとその言語にはBoost's implementationが含まれています。

+0

'opaque typedef'は解決策の一部と思われますが、名前付きパラメータイディオムはオプションのパラメータを助けるようです。 – SirGuy

+0

@GuyGreer名前付きパラメータは、文字通りパラメータの名前を付けています。これは 'foo(.a = 7、.b = 4)'(提案が承認されたと仮定した場合)や 'foo().a(7).b(4)'のような他のメカニズムです。あなたはパラメータを命名するのではなく、(タイプシステムのように)それらを入力しています。 – Barry

+0

これはおそらく_namedパラメータidiom_と呼ばれ、他の言語が直接サポートする動作をエミュレートすることで構成されています。 – SirGuy

関連する問題