c++boostboost-variantstatic-visitor

boost::variant apply static_visitor to certain types


I have the following variant:

typedef boost::variant<int, float, bool> TypeVariant;

And I want to create a visitor to convert a int or float type to a bool type.


struct ConvertToBool : public boost::static_visitor<TypeVariant> {

    TypeVariant operator()(int a) const {
        return (bool)a;
    }

    TypeVariant operator()(float a) const {
        return (bool)a;
    }
};

However this is giving me the error message:

'TypeVariant ConvertToBool::operator ()(float) const': cannot convert argument 1 from 'T' to 'float'

What is the correct way of allowing a visitor to only apply to certain types?


Solution

  • Just include the missing overload:

    Live On Coliru

    #include <boost/variant.hpp>
    #include <iostream>
    
    using TypeVariant = boost::variant<int, float, bool>;
    
    struct ConvertToBool {
        using result_type = TypeVariant;
        TypeVariant operator()(TypeVariant const& v) const {
            return boost::apply_visitor(*this, v);
        }
    
        TypeVariant operator()(int   a) const { return a != 0; }
        TypeVariant operator()(float a) const { return a != 0; }
        TypeVariant operator()(bool  a) const { return a; }
    } static constexpr to_bool{};
    
    int main() {
        using V = TypeVariant;
        
        for (V v : {V{}, {42}, {3.14f}, {true}}) {
            std::cout << v << " -> " << std::boolalpha << to_bool(v) << "\n";
        }
    }
    

    Generalize

    In more general cases you can supply a catch-all template overload:

    template <typename T> TypeVariant operator()(T const& a) const {
        return static_cast<bool>(a);
    }
    

    In fact in your trivial case that's all you needed anyways:

    Live On Coliru

    #include <boost/variant.hpp>
    #include <iostream>
    
    using TypeVariant = boost::variant<int, float, bool>;
    
    struct ConvertToBool {
        using result_type = TypeVariant;
        TypeVariant operator()(TypeVariant const& v) const {
            return boost::apply_visitor(*this, v);
        }
    
        template <typename T> TypeVariant operator()(T const& a) const {
            return static_cast<bool>(a);
        }
    } static constexpr to_bool{};
    
    int main() {
        using V = TypeVariant;
    
        for (V v : { V{}, { 42 }, { 3.14f }, { true } }) {
            std::cout << v << " -> " << std::boolalpha << to_bool(v) << "\n";
        }
    }
    

    Still prints

    0 -> false
    42 -> true
    3.14 -> true
    true -> true