Search code examples
c++c++17variant

"Invalid conversion" error when visiting a variant of functions


I am trying to std::visit a std::variant of std::function types.

Why does the following code not compile:

#include <functional>
#include <variant>

int main()
{
  std::variant<
      std::function< int () >,
      std::function< float () >
  > func_variant {std::in_place_index<0>, [] () { return 42; }};

  auto object = std::visit( [] (auto& func) { return func(); }, func_variant);

  return 0;
}

The error happens in the call of std::visit, where it says:

error: invalid conversion from ‘std::__success_type<float>::type (*)(main()::<lambda(auto:1&)>&&, std::variant<std::function<int()>, std::function<float()> >&)’ {aka ‘float (*)(main()::<lambda(auto:1&)>&&, std::variant<std::function<int()>, std::function<float()> >&)’} to ‘int (*)(main()::<lambda(auto:1&)>&&, std::variant<std::function<int()>, std::function<float()> >&)’ [-fpermissive]
       { return _Array_type{&__visit_invoke}; }
                                           ^

Solution

  • Each of your std::function types returns a different type, so the return type of the lambda you are passing to std::visit depends on the type of the selected element of the lambda. This means that the auto-type-deduction can't work, as the call to std::visit must have a single return type which is independent of which element of the variant is active.

    You could make a return type variant: using returns=std::variant<int,float> and then cast the return in your lambda to that:

    using returns=std::variant<int,float>;
    auto object = std::visit( [] (auto& func) { return returns(func()); }, func_variant);
    

    That way the return type of your lambda is the same in all cases, but you will then need to query the result to see what you got.