简体   繁体   English

将枚举映射到模板类型

[英]Mapping an enum to a template type

I have a type ValueWrapper , which can store one of several value types, identified by an enum:我有一个类型ValueWrapper ,它可以存储由枚举标识的几种值类型之一:

enum class Type : uint32_t
{
    Float = 0,
    String,
    // etc
};

struct ValueWrapper
{
    ValueWrapper(float f)
        : type{Type::Float},data{std::make_shared<float>(f)}
    {}
    ValueWrapper(std::string str)
        : type{Type::String},data{std::make_shared<std::string>(str)}
    {}
    Type type;
    std::shared_ptr<void> data;
};

Now I want to define a bunch of functions that take a ValueWrapper as argument and redirect the actual value to another function, eg:现在我想定义一堆以ValueWrapper作为参数并将实际值重定向到另一个 function 的函数,例如:

void print(const ValueWrapper &v)
{
    switch(v.type)
    {
    case Type::Float:
        std::cout<<*static_cast<float*>(v.data.get());
        break;
    case Type::String:
        std::cout<<*static_cast<std::string*>(v.data.get());
        break;
    }
}

size_t size_of(const ValueWrapper &v)
{
    switch(v.type)
    {
    case Type::Float:
        return sizeof(float);
    case Type::String:
        return sizeof(std::string);
    }
}

template<typename TFrom>
    bool is_convertible(Type tTo)
{
    switch(tTo)
    {
    case Type::Float:
        return std::is_convertible_v<TFrom,float>;
    case Type::String:
        return std::is_convertible_v<TFrom,std::string>;
    }
}

Problem is, I have quite a lot of types and functions, and I'd rather not have to do an overly long switch-case for every single one.问题是,我有很多类型和功能,我宁愿不必为每一个都做一个过长的 switch-case。

Is there some way I could do something like this instead (pseudo-code) with modern C++, so I only have to do the switch-case once to determine the actual type?:有没有什么方法可以用现代 C++ 代替(伪代码)做这样的事情,所以我只需要做一次 switch-case 来确定实际类型吗?:

type TO_TEMPLATE_TYPE(Type t)
{
    switch(t)
    {
    case Type::Float:
        return float;
    case Type::String:
        return std::string;
    }
}

template<typename TFrom>
    bool is_convertible(Type tTo)
{
    return std::is_convertible_v<TFrom,TO_TEMPLATE_TYPE(tTo)>;
}

Use a using ValueWrapper=std::variant<double,std::string,...> instead.改用using ValueWrapper=std::variant<double,std::string,...>

void print(const ValueWrapper &v)
{
  std::visit([](auto const& val){ std::cout<<val; }, v );
}

if you want shared ownership logic, make it either a variant of shared ptr, or a shared ptr to a variant.如果您想要共享所有权逻辑,请将其设为共享 ptr 的变体,或将其设为变体的共享 ptr。

I mean, you can reinvent the wheel, but why?我的意思是,你可以重新发明轮子,但为什么呢?

If you are completely opposed to changing layout, the next thing I'd do is make a variant of如果您完全反对更改布局,那么我要做的下一件事就是制作

template<class T>struct tag_t{using type=T;};
template<class T>constexpr tag_t<T> tag={};

tag_t<double> etc, map the enum manually to the variant, and then use visit to get the tag_t<T> tag_t<double> etc, map enum 手动到variant,然后使用visit获取tag_t<T>

std::variant<tag_t<double>,tag_t<std::string>> get_tag(Type e){
  switch (e){
    case Type::Float: return tag<double>;
    case Type::String: return tag<std::string>;
  }
}

etc ETC

void print(ValueWrapper const& v){
  auto tag=get_tag(v.type);
  std::visit([&](auto tag){
    using T=decltype(tag)::type;
    T* p=static_cast<T*>(v.data.get());
    std::cout<<*p;
  }, tag);
}

this technique is 100s of times easier than doing it manually;这种技术比手动操作要容易 100 倍; I have done both.我都做过。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM