【问题标题】:Can I specify the list of types for a variant using traits?我可以使用特征指定变体的类型列表吗?
【发布时间】:2018-06-05 15:55:11
【问题描述】:

我正在试验一些静态多态技术和 c++17 模板。我已经设法使用 CRTP 实现了多态性,然后使用了一个变体容器来存储我的类型,这样它们就不需要一个通用的基类(这会让我回到运行时多态性)。

#include <iostream>
#include <memory>
#include <vector>
#include <variant>

template <typename T>
class Animal
{
public:
    virtual ~Animal() = default;
    void noise()
    {
        derived()->noiseImpl();
    }
private:
    void noiseImpl()
    {
        std::cout<<"Animal animal!\n";
    }

    T* derived() {return static_cast<T*>(this);}
};

class Dog : public Animal<Dog>
{
private:
    friend Animal;
    void noiseImpl()
    {
        std::cout<<"Woof woof!\n";
    }
};

class Cat : public Animal<Cat>
{
private:
    friend Animal;
    void noiseImpl()
    {
        std::cout<<"Meow meow!\n";
    }
};

template <
    typename T,
    typename TD = std::decay_t<T>,
    typename = typename std::enable_if_t<std::is_base_of_v<Animal<TD>, TD>>
    >
void pet(T&& animal)
{
    animal.noise();
}

int main()
{
    std::vector<std::variant<Dog, Cat>> animals;
    animals.emplace_back(Dog{});
    animals.emplace_back(Cat{});

    for (auto& a : animals)
    {
        std::visit([](auto&& arg) 
        {
            pet(arg);
        }, a);
    }
}

上面的例子和你期望的一样,但是我现在想做的是不需要指定变体的类型。相反,我希望编译器确定从 Animal 继承的所有类型并创建一个可以容纳所有这些类型的变体。这类似于 pet 函数使用 is_base_of 所做的事情,只允许将动物传递给函数。我不确定这是否可能?

【问题讨论】:

    标签: c++ templates c++17 variant crtp


    【解决方案1】:

    我认为不可能自动确定从基类继承的所有类。一般是无法实现的,因为不同的继承类可以定义在不同的编译单元中。

    您可以做的是在某些 MPL 类型序列中“注册”这些继承的类,然后使用它来定义您的 variant 类型。例如boost::hana:

    constexpr auto types = boost::hana::tuple_t<char, short, int, long>;
    using variant = decltype(boost::hana::unpack(
       types, boost::hana::template_<std::variant>))::type;
    static_assert(std::is_same_v<variant, std::variant<char, short, int, long>>);
    

    在你的情况下是:

    constexpr auto types = boost::hana::tuple_t<Dog, Cat>;
    

    【讨论】:

    • 啊,这看起来很方便,但我试图允许从 Animal 派生的用户定义类型可以存储在容器中,而无需预先指定所有这些类型。类似于使用 Animal* 存储它们,但我正在看看是否可以避免使用运行时多态性。
    • @nitronoid 你可以使用类型擦除技术来做到这一点,例如,cplusplus.com/articles/oz18T05o。运行时多态性无法避免,但它隐藏在用户内部。寻找std::vector&lt;Object&gt; backpack;,这将是你的动物载体。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-05
    • 1970-01-01
    • 2014-01-09
    • 2013-06-28
    • 2014-11-26
    • 1970-01-01
    相关资源
    最近更新 更多