2

ジェネリック型のパラメーターのリスト(ParameterList)を保持するためのクラスがあります。多くのクラスは通常、コンストラクターでParameterListを受け入れますが、いくつかのクラスは少数のパラメーターのみを必要とするため、簡略化されたバージョンも提供したいと思います。

問題はこの2番目のバージョンにあります。典型的な使用法を示す例を書きました。

#include <string>
#include <map>
#include <memory>
#include <vector>
#include <iostream>

struct Parameter
{
};

template<typename T>
struct TypedParameter : public Parameter
{
    TypedParameter (const T& data): data(data){};
    T data;
};

struct ParameterList
{
    std::map<std::wstring, std::shared_ptr<Parameter>> list;

    template<class T> void addParameter(const std::wstring& name, const T& param)
    {
        list[name] = std::shared_ptr<Parameter>(new TypedParameter<T>(param));
    }

    template<class T> T& getParameter(const std::wstring& name) const
    {
        return static_cast<TypedParameter<T>*>(list.at(name).get())->data;
    }
};

class Test
{
private:
    /*const*/ ParameterList _param;
protected:
public:
    Test(ParameterList p):
        _param(p)
    {
    }

    Test(const std::wstring& name, int age)
    {
        _param.addParameter<std::wstring>(L"name", name);
        _param.addParameter<int>(L"age", age);
    }

    void Present()
    {
        std::wcout << L"My name is " << _param.getParameter<std::wstring>(L"name");
        std::wcout << L" and I'm " << _param.getParameter<int>(L"age") << L" years old." << std::endl;
    }
};

int main()
{
    ParameterList l;

    l.addParameter<int>(L"age", 16521);
    l.addParameter<std::wstring>(L"name", L"Bahamut");

    std::wcout << L"name: " << l.getParameter<std::wstring>(L"name") << std::endl;
    std::wcout << L"age: " << l.getParameter<int>(L"age") << std::endl;

    Test t1(l);
    Test t2(L"Tiamat", 15525);

    t1.Present();
    t2.Present();

    getchar();
}

t2は機能しますが、主に2つの問題があります。最初に新しいコンストラクターを作成する必要があり、次に「_param」をconstにすることをあきらめる必要があります。

次のような新しいコンストラクターをParameterListに追加することを考えていました。

template<typename... Values>
ParameterList(std::initializer_list<std::wstring> keys, const Values&... values)
{
    //?
}

//Later
Test t3({L"name", L"age"}, L"Vorel", 19870);

しかし、どうすれば値を正しく解凍できますか?

4

2 に答える 2

3

std::initializer_listコンパイル時の可変数の引数を受け入れる非テンプレート関数を作成するためのものです。可変個引数パックを。でミラーリングしても意味がありませんinitializer_list

タプルまたはペアのパックを作成してみてください。

template<typename... Values>
ParameterList(std::pair< std::wstring, Values > const &... keyvalues)

Test t3(std::make_pair(L"name", L"Vorel"), std::make_pair(L"age", 19870));

異なる引数はで生成する必要がありmake_pair、braced-init-listから推定することはできません。これは、std::initializer_listがすべて同じタイプの要素を持っている必要があるためです。また、テンプレート引数をstd::pairbraced-init-listから推定することも、コンパイラーは、与えられたオーバーロードがそもそも適切であるとさえ理解します。

于 2012-11-17T06:51:08.460 に答える
3

他の回答のように、余分なstd :: pairを使用せずに、元々やりたかったことを実行できます。1つのステップで引数を抽出するだけです。1つは名前用、もう1つは値用です。

struct ParameterList
{
    template <class... NamedParams>
    ParameterList(NamedParams... namedParams)
    {
        buildList(namedParams...);
    }
//...
private:
    template <class... NamedParams>
    void buildList() {}
    template <class Name, class Value, class... NamedParams>
    void buildList(Name name, Value value, NamedParams... restParams)
    {
        addParameter(name, value);
        buildList(restParams...);
    }
 };

次に、テストクラスで、これを使用します。

class Test
{
private:
    const ParameterList _param;
protected:
public:
    Test(ParameterList p):
        _param(p)
    {
    }

    Test(const std::wstring& name, int age) : _param(L"name", name, L"age", age)
    {
    }

//...
};

ここideoneでの完全な実例。

于 2012-11-18T13:34:57.320 に答える