Ответ 1
variant
шаблон конструктора преобразования использует разрешение перегрузки, чтобы определить, какой тип должен иметь построенный объект. В частности, это означает, что если преобразования с этими типами одинаково хороши, конструктор не работает; в вашем случае это работает, если только одна из спецификаций std::function
является конструктивной из вашего аргумента.
Итак, когда function<...>
конструктивно из данного аргумента? Начиная с С++ 14, если аргумент вызываем с типами параметров и выводит тип конвертируемый в тип возвращаемого значения. Обратите внимание, что в соответствии с этой спецификацией, если тип возврата void
, все идет (как любое выражение может быть преобразовано в void
с помощью static_cast
). Если у вас есть function
, возвращающий void
, функтор, который вы передаете, может вернуть что-нибудь, а не какую-то ошибку! Именно поэтому function<void(int)>
применим для f1
. С другой стороны, future<int>
не преобразуется в future<void>
; следовательно, только function<void(int)>
является жизнеспособным, а индекс варианта равен 1.
Однако во втором случае lambda возвращает future<void>
, который можно конвертировать в оба future<void>
и void
. Как упоминалось выше, это приводит к тому, что специализации function
являются жизнеспособными, поэтому variant
не может решить, какой из них следует построить.
Наконец, если вы отредактируете возвращаемый тип на int
, вся эта проблема преобразования void
будет устранена, поэтому все будет работать так, как ожидалось.