variadic模板内从lambda到std::函数的隐式转换
implicit convert from lambda to std::function inside variadic template
我想实现一个以lambda为参数的模板函数。
#include <functional>
template<typename ... Result> using Fun = std::function<void(Result ...)>;
template<typename ... Result> void yield(Fun<Result ...>&& body) {};
template <typename T>
struct identity {
typedef T type;
};
template<typename ... Result> void yield2(typename identity<Fun<Result ...>>::type && body) {};
int main() {
yield<char>(
Fun<char>(
[](char) -> void {} // 1. success
)
);
yield2<char>(
[](char) -> void {} // 2. success with identify
);
yield<char>(
[](char) -> void {} // 3. fail, seems achievable
);
yield(
[](char) -> void {} // 4. fail, impossible ?
);
return 0;
}
为什么情况3失败?我已经给模板提供了模板参数,所以它应该能够推导出函数类型,并将lambda隐式转换为函数
编辑:
编译器总是从函数参数中减少模板参数,我们能反过来吗?
yield<char>(
[](auto&& c) -> void {} // 5. is it possible ?
);
问题是,您有一个可变模板,它开始尝试查看除了显式char
参数之外,它还可以推断出"什么"。
如果你有一个这样的单一参数模板:
template<typename Result> using Fun = std::function<void(Result)>;
template<typename Result> void yield(Fun<Result>&& body) {};
你会注意到
yield<char>(
[](char) -> void {} // 3. fail, seems achievable
);
完全没有问题,因为std::function
的整体是可推导的。
但一旦我们制作了一个可变模板,我们的编译器就会不高兴:
template<class... Result> using Fun = std::function<void(Result...)>;
template<class... Result> void yield(Fun<Result...>&& body) {};
这是因为,不管你喜不喜欢,编译器将尝试为Fun<Result...>
推导出更多的模板参数,给定传入的值([temp.execure.type])。
yield2
回避了这个问题,因为它将生成的类型放置在非推导的上下文中,但由于您显式指定了模板参数,它将只使用那些显式指定的参数(char
)来推导类型(#1的作用原理基本相同)。
我认为最好的解决方法是yield2
尝试,但您也可以这样做,以防止传递的值参与类型推导:
auto fn = &yield<char>;
fn(
[](char) -> void {}
);
另一种解决方法是将您对yield
的调用static_cast
转换为正确的类型:(实际上,我只是在阅读"非推导上下文是:"下的其他可能的解决方案,用于[temp.dexeract.type])
using fn_type = void(*)(Fun<char>&&);
static_cast<fn_type>(&yield)(
[](char) -> void {}
);
编辑:最后,您可以编写一些额外的样板模板,使调用看起来更好(接近您的#4)。请记住,这是一个不完整的impl,例如:
此模板的目标是检测lambda的operator()
函数并提取其返回类型和参数,以便在调用yield
时可以显式指定Fun
类型(提取返回类型是不必要的,因为您只使用过void
):
首先是一个帮助结构,它将允许我们检测不可变lambda的返回类型和参数类型:
template<class T>
struct Fun_Type;
template<class C, class Ret, class... Args>
struct Fun_Type<Ret(C::*)(Args...) const>
{
using type = Fun<Args...>;
};
第二,我们的助手函数call_yield
,它将Fun_Type<...>::type
传递给对yield
:的调用
template<class ImmutableLambda>
void call_yield(ImmutableLambda&& c)
{
using Fun_t = typename Fun_Type<decltype(&ImmutableLambda::operator())>::type;
yield(Fun_t{std::forward<ImmutableLambda>(c)});
}
现在我们可以简单地称之为:
int main() {
call_yield(
[](char) -> void {}
);
}
演示(C++11)
- 如何使用Rcpp将R函数转换为C++函数
- C++函数转换为 C# 函数
- 将 C 函数转换为 C++ 以检查数字是否有效
- C++:从重载函数转换为 std::function
- 将 C 函数转换为C++语言
- C++隐式构造函数转换,后跟类型向上转换
- 将 lambda 函数转换为具有混合 lambda 引入器和参数列表的函子结构
- 通过 Boost Python 将 Python 函数转换为 C++,用作回调
- 如何将 MATLAB 图像处理库内置函数转换为 MATLAB 编码器代码生成不支持的 C++?
- 如何将函数转换为 lambda 函数
- 自定义函数转换错误?
- 将 C# 哈希函数转换为C++
- 将 lambda 函数转换为另一个编译单元中的普通函数会缩短编译时间吗?
- 加快 R 性能或将 R 函数转换为C++函数
- 将成员函数转换为指向成员函数的指针
- 将MATLAB炒作函数转换为C
- Rcpp - 用二进制函数转换数字向量?
- C lambda函数转换误差
- 此语法中的构造函数转换错误
- 将函数转换为find_if lambda