Search code examples
c++templatesvariant

how to write an overloaded with ignore feature while visit a variant


below is my code:

#include <iostream>
#include <string>
#include <vector>
#include <variant>

struct ignore
{
    template <typename T>
    void operator()([[maybe_unused]]const T&)
    {
        std::cout << "other type" << std::endl;
    }
};

template <class... Ts>
struct overloaded_ignore : ignore, Ts...
{
    overloaded_ignore(Ts...) : ignore(){}
    using Ts::operator()...;
    using ignore::operator();
};

int main()
{
    std::variant<int,float,std::string> my_var = std::string("helloworld");
    // std::variant<int,float,std::string> my_var = 5.0F;
    // std::variant<int,float,std::string> my_var = 3;


    std::visit(overloaded_ignore{
        [](const int& t)
        {
            std::cout << "int var: " << t << std::endl;
        },
        [](const std::string& t)
        {
            std::cout << "string var: " << t << std::endl;
        }
        }, my_var);

    
    return 0;
}

I expect to output "string var: helloworld", but the "other type" is outputed. how to fix this. please note, the ignored "operator ()" is needed.

string var: helloworld is expected.


Solution

  • Just add the const-qualifier to ignore::operator() as the lambda's operator() is const-qualified by default:

    struct ignore
    {
        template <typename T>
        void operator()([[maybe_unused]]const T&) const // <--
        {
            std::cout << "other type" << std::endl;
        }
    };
    
    template <class... Ts>
    struct overloaded_ignore : ignore, Ts...
    {
        overloaded_ignore(Ts...) : ignore(){}
        using Ts::operator()...;
        using ignore::operator();
    };
    

    Demo

    (Since overloaded_ignore{...} is a prvalue, this makes the non-const ignore::operator() a better match before)