我有一个用于保存泛型类型参数列表的类(ParameterList)。 许多类通常在构造函数中接受ParameterList,但有些只需要几个参数,所以我也想提供一个简化版本。
问题在于第二个版本。我写了一个例子来展示一个典型的用法:
#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有效,但主要有两个问题。首先,我必须创建一个新的构造函数,然后我必须放弃使“_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);
但是如何正确解压缩值呢?
答案 0 :(得分: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::pair
的模板参数{1}}不能从braced-init-list推导出来,编译器甚至也不能确定给定的重载是否恰当。
答案 1 :(得分:3)
你可以在没有额外std :: pair的情况下做你想做的事,就像在其他答案中一样。只需一步提取参数 - 一个用于名称,一个用于值。
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...);
}
};
然后在Test类中,使用它:
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)
{
}
//...
};
完整的工作示例here at ideone。