没有将 lambda 函数参数与模板函数匹配的函数调用
No matching function call for lambda function parameter to template function
尝试将 lambda 函数传递给以传递函数的函数参数为模板的模板工厂函数导致 gcc-10.2.0 报告 no matching function for call to ‘test(main()::<lambda(int, double)>)’
.
当我在 lambda 函数前面添加一个 +
强制转换为函数指针时,它似乎确实有效,但我不明白为什么有必要这样做。为什么转换不会自动发生?有什么办法可以做到这一点吗?
我也试过 std::function<void(TArgs...)> test_func
作为 make_test
声明中的参数,但是这给了我同样的 no matching function for call
错误。
#include <iostream>
template <typename... TArgs>
struct test_type {
test_type(void(TArgs...)) {};
};
template <typename... TArgs>
test_type<TArgs...> make_test(void test_func(TArgs...)) {
return test_type<TArgs...>{test_func};
}
int main() {
auto test_object = make_test([](int a, double b) { std::cout << a << b << "\n"; });
return 0;
}
编辑
我想知道是否有某种方法可以使其与类型特征一起使用。像下面这样的东西。虽然我知道没有办法从模板参数中获取参数列表。
template <typename F>
test_type<get_arg_list<F>> make_test(std::function<F>&& f) {
return test_type<get_arg_list<F>>{std::forward(f)};
}
为了支持传递给工厂的各种可调用对象(例如,有状态的 lambda 或函数指针),您的 test_type
构造函数应该接受某种类型擦除的函数类型,例如 std::function<void(int, double)>
:
template<class... TArgs>
struct test_type {
test_type(std::function<void(TArgs...)>) {};
};
之后,只需编写样板来处理以下传递给 make_test
的可调用对象
- 常规函数指针
- 一个 lambda(具有
operator()(...) const
的结构)
- 一个可变的 lambda 或一个没有
const
operator()
函数的用户定义的可调用函数
这是一种使用类型特征的方法:
从一个基础 class 开始,我们将专门针对每个场景:
template<class T, class = void>
struct infer_test_type;
(这是 voider 模式的常见设置。我们可以通过概念和约束来做到这一点,但我懒得查语法,也许以后再看)
常规函数指针特化
template<class Ret, class... Args>
struct infer_test_type<Ret(*)(Args...)>
{
using type = test_type<Args...>;
};
现在我们可以为简单起见编写一个模板化别名:
template<class T>
using infer_test_type_t = typename infer_test_type<T>::type;
我们可以验证它是这样工作的:
void foo(int, double){}
// ...
static_assert(std::is_same_v<infer_test_type_t<decltype(&foo)>, test_type<int, double>>);
我们可以像这样为 make_test
函数使用类型特征:
template<class T>
auto make_test(T&& callable) -> infer_test_type_t<T>
{
return infer_test_type_t<T>{std::forward<T>(callable)};
}
现在只需涵盖我们的其他两个场景。
可调用对象
- 这些将有 operator()(
const
或没有)
我将从顶级特征开始检测 operator()
的存在并将 operator()
的类型输入另一个特征。
顶级特征:
// if T is a callable object
template<class T>
struct infer_test_type<T, std::void_t<decltype(&T::operator())>>
{
using type = typename infer_test_type<decltype(&T::operator())>::type;
};
你看到它在内部回调到我还没有展示的另一个 infer_test_type
专业化;专门用于 operator()
的一种。我现在将展示这两个专业:
// if operator() is a const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...) const>
{
using type = test_type<Args...>;
};
// if operator() is non-const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...)>
{
using type = test_type<Args...>;
};
(如果我们想更聪明一点,我们可以将这两者结合起来,并在跟注之前在高级别去掉任何 const
,但我认为这更清楚)
现在我们应该能够为 非泛型 可调用对象(没有泛型 lambda 或模板化 operator()
函数)推断出合适的 test_type
:
一个非常量测试 operator()
:
struct my_callable
{
void operator()(int, double) // non-const
{
}
};
// ...
static_assert(std::is_same_v<infer_test_type_t<my_callable>, test_type<int, double>>);
并使用您的 lambda 进行测试:
auto lambda = [](int a, double b) { std::cout << a << b << "\n"; };
static_assert(std::is_same_v<infer_test_type_t<decltype(lambda)>, test_type<int, double>>);
综合起来
对于您的简单(非捕获、非通用 lambda)示例,它非常简单:
make_test([](int a, double b) { std::cout << a << b << "\n"; });
Demo
尝试将 lambda 函数传递给以传递函数的函数参数为模板的模板工厂函数导致 gcc-10.2.0 报告 no matching function for call to ‘test(main()::<lambda(int, double)>)’
.
当我在 lambda 函数前面添加一个 +
强制转换为函数指针时,它似乎确实有效,但我不明白为什么有必要这样做。为什么转换不会自动发生?有什么办法可以做到这一点吗?
我也试过 std::function<void(TArgs...)> test_func
作为 make_test
声明中的参数,但是这给了我同样的 no matching function for call
错误。
#include <iostream>
template <typename... TArgs>
struct test_type {
test_type(void(TArgs...)) {};
};
template <typename... TArgs>
test_type<TArgs...> make_test(void test_func(TArgs...)) {
return test_type<TArgs...>{test_func};
}
int main() {
auto test_object = make_test([](int a, double b) { std::cout << a << b << "\n"; });
return 0;
}
编辑
我想知道是否有某种方法可以使其与类型特征一起使用。像下面这样的东西。虽然我知道没有办法从模板参数中获取参数列表。
template <typename F>
test_type<get_arg_list<F>> make_test(std::function<F>&& f) {
return test_type<get_arg_list<F>>{std::forward(f)};
}
为了支持传递给工厂的各种可调用对象(例如,有状态的 lambda 或函数指针),您的 test_type
构造函数应该接受某种类型擦除的函数类型,例如 std::function<void(int, double)>
:
template<class... TArgs>
struct test_type {
test_type(std::function<void(TArgs...)>) {};
};
之后,只需编写样板来处理以下传递给 make_test
- 常规函数指针
- 一个 lambda(具有
operator()(...) const
的结构) - 一个可变的 lambda 或一个没有
const
operator()
函数的用户定义的可调用函数
这是一种使用类型特征的方法:
从一个基础 class 开始,我们将专门针对每个场景:
template<class T, class = void>
struct infer_test_type;
(这是 voider 模式的常见设置。我们可以通过概念和约束来做到这一点,但我懒得查语法,也许以后再看)
常规函数指针特化
template<class Ret, class... Args>
struct infer_test_type<Ret(*)(Args...)>
{
using type = test_type<Args...>;
};
现在我们可以为简单起见编写一个模板化别名:
template<class T>
using infer_test_type_t = typename infer_test_type<T>::type;
我们可以验证它是这样工作的:
void foo(int, double){}
// ...
static_assert(std::is_same_v<infer_test_type_t<decltype(&foo)>, test_type<int, double>>);
我们可以像这样为 make_test
函数使用类型特征:
template<class T>
auto make_test(T&& callable) -> infer_test_type_t<T>
{
return infer_test_type_t<T>{std::forward<T>(callable)};
}
现在只需涵盖我们的其他两个场景。
可调用对象
- 这些将有 operator()(
const
或没有)
我将从顶级特征开始检测 operator()
的存在并将 operator()
的类型输入另一个特征。
顶级特征:
// if T is a callable object
template<class T>
struct infer_test_type<T, std::void_t<decltype(&T::operator())>>
{
using type = typename infer_test_type<decltype(&T::operator())>::type;
};
你看到它在内部回调到我还没有展示的另一个 infer_test_type
专业化;专门用于 operator()
的一种。我现在将展示这两个专业:
// if operator() is a const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...) const>
{
using type = test_type<Args...>;
};
// if operator() is non-const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...)>
{
using type = test_type<Args...>;
};
(如果我们想更聪明一点,我们可以将这两者结合起来,并在跟注之前在高级别去掉任何 const
,但我认为这更清楚)
现在我们应该能够为 非泛型 可调用对象(没有泛型 lambda 或模板化 operator()
函数)推断出合适的 test_type
:
一个非常量测试 operator()
:
struct my_callable
{
void operator()(int, double) // non-const
{
}
};
// ...
static_assert(std::is_same_v<infer_test_type_t<my_callable>, test_type<int, double>>);
并使用您的 lambda 进行测试:
auto lambda = [](int a, double b) { std::cout << a << b << "\n"; };
static_assert(std::is_same_v<infer_test_type_t<decltype(lambda)>, test_type<int, double>>);
综合起来
对于您的简单(非捕获、非通用 lambda)示例,它非常简单:
make_test([](int a, double b) { std::cout << a << b << "\n"; });