简体   繁体   English

如何使用可变参数模板通过 std::visit 处理 std::variant?

[英]How to use variadic templates to proceed std::variant with std::visit?

I'm trying to write a logic, with usage of command and factory patterns.我正在尝试使用命令和工厂模式来编写逻辑。 Based on a data inside the std::variant I want to create an object.基于std::variant的数据,我想创建一个对象。 It may look like a map of C++ types.它可能看起来像 C++ 类型的映射。

Here is the code: Wandbox这是代码: Wandbox

I can hardcode all used types but I want to automate it with variadic templates, how to do it?我可以对所有使用的类型进行硬编码,但我想使用可变参数模板将其自动化,该怎么做?

#include <cassert>
#include <variant>
#include <type_traits>
#include <memory>
#include <iostream>


struct IFace
{
    virtual void foo() = 0;
};

template<typename TKey, typename TValue>
struct Base : IFace
{
    using Key = TKey;
    using Value = TValue;
};

struct Int : Base<int, Int>
{
    void foo() override { std::cout << "Int"; }
};

struct Double : Base<double, Double>
{
    void foo() override { std::cout << "Double"; }
};

using Var = std::variant<int, double>;

template<typename ...Args>
std::shared_ptr<IFace> factory(const Var& v)
{
    std::shared_ptr<IFace> p;

    std::visit([&p](auto&& arg){
        using TKey = std::decay_t<decltype(arg)>;
        // TODO: use variadic instead of hardcoded types
        if constexpr (std::is_same_v<TKey, int>)
        {
            using TValue = typename Base<TKey, Int>::Value;
            p = std::make_shared<TValue>();
            std::cout << "int ";
        }
        else if constexpr (std::is_same_v<TKey, double>)
        {
            using TValue = typename Base<TKey, Double>::Value;
            p = std::make_shared<TValue>();
            std::cout << "double ";
        }
    }, v);

    return p;
}


int main()
{
    const Var v = 42;
    auto p = factory<Int, Double>(v);

    assert(p != nullptr);
    p->foo();

    return 0;
}

This popular little "overloaded" class is always useful for passing lambdas to std::visit :这个流行的小“重载”类对于将 lambdas 传递给std::visit总是有用的:

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

Then, instead of using a generic lambda and trying to deduce the right object type from the parameter type, just generate an overload for each Args .然后,不要使用泛型 lambda 并尝试从参数类型推导出正确的对象类型,只需为每个Args生成一个重载。

template<typename ...Args>
std::shared_ptr<IFace> factory(const std::variant<typename Args::Key...>& v)
{
    return std::visit(overloaded { 
        [](const typename Args::Key&) -> std::shared_ptr<IFace> { return std::make_shared<Args>(); }... 
    }, v);
}

Demo: https://godbolt.org/z/nKGf3c演示: https : //godbolt.org/z/nKGf3c

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

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