我有一个带有可变参数模板参数的类,我正在尝试编写一个成员函数来创建一个包含可变参数的容器。我的方法是从参数创建一个元组,以便展开元组的元素,并调用一个函数来获取元素,将它们添加到我的容器类中,请参阅以下代码(抱歉,示例很长,有点复杂)我不知道要进一步归结):
#include <string>
#include <tuple>
#include <vector>
#include <map>
#include <memory>
#include <iostream>
// these are a couple of mock-up classes, basically we want to save entities of arbitrary parameters
// base class for a type erased parameter
struct TypeErasedParameter
{
private:
const std::string m_strId;
protected:
TypeErasedParameter(std::string id) : m_strId(id) {}
public:
virtual ~TypeErasedParameter() {}
const std::string & GetId()
{
return m_strId;
}
template <typename T>
T& GetValue();
};
// implementation of the type erased parameter, storing the parameter T in parameterValue
template <typename T>
struct Parameter : public TypeErasedParameter
{
T parameterValue;
Parameter(const std::string id, T value) : TypeErasedParameter(id), parameterValue(value) {}
};
template <typename T>
T& TypeErasedParameter::GetValue()
{
return dynamic_cast<Parameter<T>*>(this)->parameterValue;
}
// ParameterPack is basically a container that stores a bunch of TypeErasedParameters
struct ParameterPack
{
std::map<std::string, std::unique_ptr<TypeErasedParameter>> m_mapParamsById;
template<typename ParameterType>
ParameterType& GetParameter(const std::string& strParamName)
{
return m_mapParamsById.at(strParamName)->GetValue<ParameterType>();
}
template<typename ParameterType>
bool AddParameter(const std::string& strParamName, ParameterType& parameter)
{
m_mapParamsById.insert(std::make_pair(strParamName, parameter));
return true;
}
};
// actual class of interest, the creator and unpacker of parameter packs
template <typename ...Args>
struct ParameterUnpacker
{
public:
std::vector<std::string> m_vecIds;
ParameterUnpacker(std::vector<std::string> vecIds) : m_vecIds(vecIds) {}
const std::vector<std::string>& GetIds()
{
return m_vecIds;
}
template <typename Tuple, std::size_t... Is>
std::unique_ptr<ParameterPack> CreateParameterPackHelper(Tuple&& tuple, std::index_sequence<Is...>)
{
std::unique_ptr<ParameterPack> pParamPack = std::unique_ptr<ParameterPack>(new ParameterPack());
const auto& vecIds = GetIds();
// TODO: This line I'm not sure about
// my plan is to unfold the tuple passed to this function and call
// AddParameter for each element
if (!(pParamPack->AddParameter(vecIds.at(Is), std::get<Is>(tuple)) && ...))
{
return nullptr;
}
return pParamPack;
}
// with this function we want to be able to pass the parameters to our Unpacker so that it creates a
// parameterPack with the parameters in it for us
template <typename... InputArgs>
std::unique_ptr<ParameterPack> CreateParameterPack(InputArgs&... args)
{
// TODO: This line I'm also not sure about
// my way of thought is to create a tuple of the the variadic template and
// have CreateParameterPackHelper handle the rest
return CreateParameterPackHelper(std::tuple<InputArgs...>{}, std::index_sequence_for<InputArgs ...>{});
}
};
int main(int argc, char* argv[]) {
// create a new pack using ParameterUnpacker.CreateParameterPack()
ParameterUnpacker<double, int> unpacker({ "doubleParam" , "intParam" });
const double double_param = 1.123;
const int int_param= 12;
auto newParamPack = unpacker.CreateParameterPack(double_param , int_param);
return 0;
}
以下是上面的代码作为带有错误消息的示例:http://coliru.stacked-crooked.com/a/f315a81cb02f18e0
我最终不确定的是,如何确保创建 ParameterUnpacker 实例的可变参数模板(即
template <typename ...Args>
)与我传递给 unpack.CreateParameterPack(firstParam, secondParam, ...)
的模板(即 )相匹配template <typename... InputArgs>
)?如何知道我正在从哪些元组中创建要传递给 CreateParameterPackHelper 的元组?如何将每个参数添加到 unpacker.CreateParameterPack
正在创建的 ParameterPack 中?
提前非常感谢您的帮助!
有一些错误:
template <typename... InputArgs>
std::unique_ptr<ParameterPack> CreateParameterPack(InputArgs&... args)
{
return CreateParameterPackHelper(std::tuple<InputArgs...>{args...},
// ^^^^^^^
std::index_sequence_for<InputArgs ...>{});
}
您忘记使用
args
。
template <typename ParameterType>
bool AddParameter(const std::string& strParamName, const ParameterType& parameter)
{
m_mapParamsById[strParamName] = std::make_unique<Parameter<ParameterType>>(parameter));
return true;
}
你必须在这里构建一个
Parameter<ParameterType>
。
您使用
TypeErasedParameter
是有风险的,因为您将拥有类型不匹配的UB。
std::any
似乎更合适:
struct TypeErasedParameter
{
private:
const std::string m_strId;
std::any value;
public:
template <typename T>
TypeErasedParameter(std::string id, const T& value) : m_strId(id), value(value) {}
const std::string& GetId() { return m_strId; }
template <typename T>
T& GetValue() { return std::any_cast<T&>(value); }
};
struct ParameterPack
{
std::map<std::string, TypeErasedParameter> m_mapParamsById;
// TypeErasedParameter no longer to be pointer
template <typename ParameterType>
ParameterType& GetParameter(const std::string& strParamName)
{
return m_mapParamsById.at(strParamName).GetValue<ParameterType>();
}
template<typename T>
bool AddParameter(const std::string& strParamName, const T& parameter)
{
m_mapParamsById.emplace(strParamName, TypeErasedParameter(strParamName, parameter));
return true;
}
};