std :: visit std :: variant с перегруженной свободной функцией вместо объекта-функции

В C ++ 17 есть простой способ std :: visit варианта с перегруженной бесплатной функцией или я должен использовать объект с перегруженным оператором вызова?

Другими словами, можно ли добавить что-нибудь простое, чтобы следующая строка //ERROR! была скомпилирована так, чтобы она была функционально такой же, как строка //OK!?

#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;
}

person Timtro    schedule 10.03.2020    source источник
comment
Первый параметр std::visit не отличается от любого другого параметра: он должен быть дискретного типа.   -  person Sam Varshavchik    schedule 10.03.2020


Ответы (2)


Вы можете использовать лямбда для обработки перегрузок:

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

Демо

person Jarod42    schedule 10.03.2020
comment
Симпатичная эта маленькая полиморфная лямбда-прокладка. Я просто указал в комментарии, что мне нужно что-то тонкое (тонкий - небольшой код, очевидное намерение, отсутствие накладных расходов во время выполнения), чтобы заставить компилятор использовать свое естественное разрешение перегрузки. Я надеюсь, что компилятор оптимизирует прокладку - кажется, что должен. В таком случае это все, кроме (возможно) очевидного намерения - но я подозреваю, что это так хорошо, как есть. Спасибо! - person Timtro; 10.03.2020
comment
Отличное предложение! - person Marshall Clow; 10.03.2020

Подумайте, что вы здесь делаете: вы вызываете visit и передаете ему «то, что можно назвать».

Это всего лишь что-то, а не «все, что компилятор найдет с именем foo».

Чтобы реализовать то, о чем вы просите, компилятор должен будет автоматически создать что-то, содержащее все перегрузки foo, а затем передать его visit - и это то, что вы делаете с foo_obj

person Marshall Clow    schedule 10.03.2020
comment
Вы не ошиблись, я понимаю. Но дело в том, что компилятор должен будет автоматически построить что-то, содержащее все перегрузки, например таблицу перегрузок, что он и делает. И мне просто интересно, есть ли симпатичный трюк, позволяющий использовать в этом приложении мощность разрешения перегрузки с помощью некоторого тонкого промежуточного звена, чтобы указать на мое желание. (тонкий - небольшой код, очевидное намерение, отсутствие накладных расходов во время выполнения.) - person Timtro; 10.03.2020
comment
Компилятор не строит таблицы перегрузки - не совсем. Он создает (во время компиляции) набор всех возможных перегрузок для вызова, а затем выбирает одну из них и генерирует для нее код. Если он не может выбрать один (наилучшее совпадение), вы получите ошибку времени компиляции. - person Marshall Clow; 10.03.2020
comment
Честно говоря, я играл быстро и свободно со своими условиями, и я понимаю, почему это не работает из коробки. Я делал это с самого начала - я знал, что мне нужен «один» параметр в качестве параметра, и я искал именно его: то, что позволило бы мне сказать компилятору использовать разрешение перегрузки свободных функций, чтобы сделать выбор. И, как выясняется, можно добавить простую полиморфную лямбду, чтобы восполнить этот пробел. - person Timtro; 11.03.2020