Search code examples
c++boost-variant

Can one do type erasure with boost variant, if all options fulfill an interface?


I have some code in which every element in a boost::variant fulfills a common interface. For various reasons I don't want to store them as erased types. Is there an easy way to get at the interface, given the variant, without writing a visitor for each possible case? The specific errors I get with the below are all on the cast line, and are as follows:

error C2100: illegal indirection
error C2440: 'static_cast': cannot convert from 'animal *' to 'iAnimal *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
error C2227: left of '->speak' must point to class/struct/union/generic type

#include <iostream>
#include "Boost/variant.hpp"

class iAnimal
{
public:
    virtual std::string speak() = 0;
    virtual ~iAnimal() {};
};

struct cat : public iAnimal
{
    std::string speak()
    {
        return "Meow!";
    }
};

struct dog : public iAnimal
{
    std::string speak()
    {
        return "Woof!";
    }
};

int main()
{
    typedef boost::variant<cat, dog> animal;
    animal fluffy = cat();
    std::cout << static_cast<iAnimal*>(&*fluffy)->speak() << std::endl;
    return 0;
}

Solution

  • You might use something like:

    boost::variant<cat, dog> animal;
    animal fluffy = cat();
    boost::apply_visitor([](auto& e) -> iAnimal& { return e; }, fluffy).speak();
    

    In C++17, with std, it would be

    std::variant<cat, dog> animal;
    animal fluffy = cat();
    std::visit([](auto& e) -> iAnimal& { return e; }, fluffy).speak();