如何从可变参数模板类创建元组并在 C++ 中调用每个元素作为参数的成员函数?

问题描述 投票:0回答:1

我有一个带有可变参数模板参数的类,我正在尝试编写一个成员函数来创建一个包含可变参数的容器。我的方法是从参数创建一个元组,以便展开元组的元素,并调用一个函数来获取元素,将它们添加到我的容器类中,请参阅以下代码(抱歉,示例很长,有点复杂)我不知道要进一步归结):

#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 中?

提前非常感谢您的帮助!

c++ templates variadic-templates fold-expression
1个回答
0
投票

有一些错误:

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;
  }
};

演示

© www.soinside.com 2019 - 2024. All rights reserved.