Search code examples
c++operator-overloadingvisitor-pattern

No matching function call to std::visit() using overload pattern


I'm trying to dispatch a variant inside a variant with the visitor overload pattern. However I can't seem to fit the parameters to what is expected. I get this (truncated, for more output see compiler explorer link):

error: no matching function for call to 'visit ...'

Here's my code. What am I overlooking?

Demo

#include <variant>
#include <cstdio>

template <typename... Ts>
struct overload : Ts...
{
    using Ts::operator() ...;
};

int main() {

    struct StateA{};
    struct StateB{};
    struct StateC{};

    using state_type = std::variant<StateA, StateB, StateC>;
    auto state = state_type{StateA{}};

    struct EventA{};
    struct EventB{};

    struct WifiConnectedNote{};
    struct ErrorNote{};

    using QueueVariantType = std::variant<std::monostate, WifiConnectedNote, ErrorNote>;
    
    using event_type = std::variant<std::monostate, QueueVariantType, EventA, EventB>;
    auto event = event_type{EventA{}};

    for (size_t i=0; i < 10; i++) {
        state = std::visit(overload{
            [&](QueueVariantType&& variant, auto&& state_tmp) -> state_type {
                std::visit(overload{
                    [&](WifiConnectedNote&&, auto&&){
                        printf("WifiConnectedNote A\n");
                    },
                    [&](ErrorNote&&, auto&&){
                        printf("ErrorNote A\n");
                    },
                    [&](auto&&, auto&&){
                        printf("Other in Queue variant\n");
                    },
                }, std::forward<decltype(variant)>(variant), std::forward<decltype(state_tmp)>(state_tmp));
                return StateC{};
            },
            [&](auto&&, const StateA&) -> state_type {
                printf("State A\n");
                return StateC{};
            },
            [&](auto&&, const StateB&) -> state_type {
                printf("State B\n");
                return StateA{};
            },
            [&](auto&&, const StateC&) -> state_type {
                printf("State C");
                return StateB{};
            },
        }, std::move(event), state);
    }
}

Solution

    • You are missing an overload case for the outer std::visit for event==std::monostate. Either provide one or remove the state from the variant type.

        [&](std::monostate, auto&& ) -> state_type {
            ; // Do stuff here
        }
      
    • state_tmp is not used in the inner std::visit. If i remove it and the auto&& from the lambda signatures, the code compiles and runs. But is this what you want ? Remember that state_tmp is not the variant type itself, but the underlying type resolved by the outer std::visit. That's why the inner visit fails.

    Hope you can take from here !