3

In C++17 is there a simple way to std::visit a variant with an overloaded free-function or must I use an object with an overloaded call operator?

In other words, is it possible to add something simple to make the following //ERROR! line compile to be functionally the same as the //OK! line?

#include<variant>
#include<iostream>
#include<list>

#include <boost/hana/functional/overload.hpp>
using boost::hana::overload;

struct A {};
struct B {};

void foo(A) { std::cout << "Got an A!\n"; }
void foo(B) { std::cout << "Got a  B!\n"; }

using AorB = std::variant<A,B>;

constexpr auto foo_obj = overload(
    [](A){std::cout << "Got an A!\n";},
    [](B){std::cout << "Got a  B!\n";});

int main() {

  std::list<AorB> list{A(), B(), A(), A(), B()};

  for (auto& each : list) std::visit(foo, each);      // ERROR!
  for (auto& each : list) std::visit(foo_obj, each);  // OK!

  return 0;
}
Timtro
  • 418
  • 5
  • 15

2 Answers2

6

You might use lambda to handle overloads:

for (auto& each : list) std::visit([](auto e){ return foo(e);}, each);

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Cute, this little polymorphic lambda shim. I was just making a point in a comment that I want something slender (slender ≈ small code, obvious intent, no runtime overhead) to force the compiler to use its natural overload resolution. I hope the compiler optimizes the shim away—it feels like it should. In that case, this is everything except (perhaps) obvious intent—but I suspect this is as good as it gets. Thanks! – Timtro Mar 10 '20 at 17:42
  • Excellent suggestion! – Marshall Clow Mar 10 '20 at 19:32
2

Think about what you're doing here: You call visit and pass it "something that can be called".

That's just one something, not "whatever the compiler can find named foo"

To implement what you're asking for, the compiler would have to automatically build some kind of thing containing all the overloads of foo, and then pass it to visit - and that's what you are doing with the foo_obj

Marshall Clow
  • 15,972
  • 2
  • 29
  • 45
  • You're not wrong, I get it. But the point is "the compiler would have to automatically build some kind of thing containing all the overloads"—like an overload table, which it does. And I'm just wondering if there is a cute trick to bring the power of overload resolution to bear in this application with some slender intermediate to indicate my desire. (slender ≈ small code, obvious intent, no runtime overhead.) – Timtro Mar 10 '20 at 17:27
  • The compiler does not "build overload tables" - not really. It builds (at compile time) a set of all possible overloads for a call, and then chooses *one* of them and generates code for that one. If it can't choose one (the "best match"), you get a compile-time error. – Marshall Clow Mar 10 '20 at 19:20
  • Fair enough, I was playing fast and loose with my terms and I understand why it doesn't work out of the box. I did from the start—I knew I needed “one” thing as a parameter, and I was looking for just that: the thing that would let me tell the compiler to use free-function overload resolution to make the choice. And, as it turns out, a simple polymorphic lambda can be shimmed in to bridge that gap. – Timtro Mar 11 '20 at 13:07