我尝试了一些静态多态技术和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
所做的事情,只允许将动物传递给函数。我不确定这是否可能?
答案 0 :(得分:0)
我认为无法自动确定从基类继承的所有类。通常,它是不可实现的,因为可以在不同的编译单元中定义不同的继承类。
您可以做的是在某些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>;