Вопрос или проблема
Передача лямбда-функции в шаблонную функцию с выведенными типами [дубликат]
У меня есть следующий пример с двумя версиями функции make, которая принимает другую функцию и выводит типы аргументов. Затем она создает структуру с шаблонным типом Signature с этой функцией.
enum class SomeEnum {
ONE = 1,
TWO = 2,
};
template <SomeEnum _Type, typename _Result, typename... _Args>
struct Signature {
static constexpr SomeEnum Type = _Type;
using Result = _Result;
using Args = std::tuple<_Args...>;
std::function<_Result (_Args...)> func;
};
template <
SomeEnum _Type,
typename _Result,
typename... _Args>
Signature<_Type, _Result, _Args...> make(
std::function<_Result (_Args...)> func) {
return Signature<_Type, _Result, _Args...>{.func = func};
}
template <SomeEnum _Type, typename _Result, typename... _Args>
Signature<_Type, _Result, _Args...> make(
_Result (*func)(_Args...)) {
return Signature<_Type, _Result, _Args...>{
.func = std::move(func)};
}
void foo(int x, std::string y, int z) {
}
auto sig1 = make<SomeEnum::ONE>(&foo);
auto sig2 = make<SomeEnum::TWO>([](int x, std::string y, int z) {
});
Эта версия работает:
auto sig1 = make<SomeEnum::ONE>(&foo);
но эта версия:
auto sig2 = make<SomeEnum::TWO>([](int x, std::string y, int z) {
});
Не работает
main.cpp:40:13: ошибка: нет подходящей функции для вызова 'make'
auto sig2 = make<SomeEnum::TWO>([](int x, std::string y, int z) {
^~~~~~~~~~~~~~~~~~~
main.cpp:23:37: примечание: кандидат шаблона игнорируется: не удалось сопоставить 'std::function<_Result (_Args...)>' с '(лямбда на main.cpp:40:33)'
Signature<_Type, _Result, _Args...> make(
^
main.cpp:29:37: примечание: кандидат шаблона игнорируется: не удалось сопоставить '_Result (*)(_Args...)' с '(лямбда на main.cpp:40:33)'
Signature<_Type, _Result, _Args...> make(
^
1 ошибка сгенерирована.
Однако, если я явно укажу тип, то это работает:
std::function<void(int x, std::string y, int z)> l = [](int x, std::string y, int z) {
};
auto sig2 = make<SomeEnum::TWO>(l);
Как я могу сделать, чтобы эта версия:
auto sig2 = make<SomeEnum::TWO>([](int x, std::string y, int z) {
});
работала? Я бы хотел иметь возможность просто передать лямбду без дополнительной типизации и позволить коду выведать типы.
<div class="s-prose js-post-body" itemprop="text">
<p><code>std::function</code> поддерживает CTAD (через свои <a href="https://en.cppreference.com/w/cpp/utility/functional/function/deduction_guides" rel="nofollow noreferrer">руководства по выводу</a>), но CTAD не применяется к параметрам функции.</p>
<p>Поэтому тип вашего параметра должен быть шаблонным (вместо <code>std::function<__></code>):</p>
<pre><code>template <typename F> void foo(F &&func) {bar(std::function(std::forward<F>(func)));}
Где bar
принимает std::function<R(P...)>
, как ваша первая перегрузка make()
.
</div>