c++ - C++ 从按顺序执行的其他 constexpr lambda 创建 lambda 不能是 constexpr
问题描述
假设我想创建一个执行其他一些 lambda 的 lambda,如下所示:
constexpr auto some_func{[]() {
// do something
}};
constexpr auto some_other_func{[]() {
// do something else
}};
constexpr auto funcs_tuple = std::tuple(some_func, some_other_func);
constexpr auto combined_funcs = do_funcs(funcs_tuple);
combined_funcs();
我已将do_funcs
功能实现为:
template <std::size_t Idx = 0, typename Tuple>
constexpr auto do_funcs(const Tuple& tup) {
return [&]() {
if constexpr (Idx < std::tuple_size_v<Tuple>) {
const auto f = std::get<Idx>(tup);
f();
do_funcs<Idx + 1>(tup)();
}
};
}
它只是按顺序执行元组中的函数。但是,结果变量combined_funcs
不能声明为 constexpr,因为funcs_tuple
调用中的引用do_funcs
不是常量表达式。
我正在使用 clang(trunk)尝试编译器资源管理器中的代码并得到
error: constexpr variable 'combined_funcs' must be initialized by a constant expression
note: reference to 'funcs_tuple' is not a constant expression
为什么这不被视为常量表达式?有没有办法让它成为 constexpr?
经过一些试验和错误后,我发现不是在返回的 lambda 中通过引用捕获元组,do_funcs
而是按值捕获结果 lambda 确实可以声明为 constexpr,但我真的不想为每个创建元组的副本递归调用do_funcs
.
constexpr auto do_funcs(const Tuple& tup) {
// capture by value instead of reference
// |
// v
return [=]() { ...
我还想制作一个辅助函数,它接受一个 lambda 参数包并将其作为元组分派给do_funcs
函数,如下所示:
template <typename... Funcs>
constexpr auto make_do_funcs(Funcs&&... fs) {
const auto funcs = std::tuple(std::forward<Funcs>(fs)...);
return do_funcs(funcs);
}
我使用元组而不是像这样的另一种方法的原因:
template <typename Func, typename... Funcs>
constexpr auto do_funcs(Func&& f, Funcs&&... fs) {
return [f = std::forward<Func>(f), ... fs = std::forward<Funcs>(fs)] {
f();
if constexpr (sizeof...(fs) > 0) {
do_funcs(fs...);
}
};
}
是因为“完美捕获”是 C++20 的一项功能,需要针对 C++17 使用元组的解决方法。
为了进一步参考,我正在尝试为我的组合解析器库创建一个实用程序“解析器”,它会在需要时执行一些其他解析器以创建更复杂的解析器。
解决方案
std::apply()
如下所示的简单(折叠逗号运算符)怎么样?
#include <iostream>
#include <tuple>
int main()
{
auto some_func_1{[]() { std::cout << "1" << std::endl; }};
auto some_func_2{[]() { std::cout << "2" << std::endl; }};
auto funcs_tuple = std::tuple{some_func_1, some_func_2};
auto do_funcs
= [](auto const & tpl)
{ std::apply([](auto ... fn){ (fn(), ...); }, tpl); };
do_funcs(funcs_tuple);
}
你可以看到你被打印出来1
了2
删除std::cout
s (不constexpr
兼容)并添加一些constexpr
,你有
#include <iostream>
#include <tuple>
int main()
{
constexpr auto some_func_1{[]() { }};
constexpr auto some_func_2{[]() { }};
constexpr auto funcs_tuple = std::tuple{some_func_1, some_func_2};
constexpr auto do_funcs
= [](auto const & tpl)
{ std::apply([](auto ... fn){ (fn(), ...); }, tpl); };
do_funcs(funcs_tuple);
}
推荐阅读
- authentication - 位置/api的Nginx配置
- neo4j - 如何将 Quarkus 配置为指向非默认名称 Neo4J DB?
- python-3.x - PyAudio 不能处理长时间的沉默
- c++ - 对“Class::Class Constructor”的未定义引用
- python-3.x - 正则表达式搜索和替换从关键字开始的任何字符串
- java - 将 JSON 数据转换为 DataFrame Apache Spark
- php - 从特定产品中排除自定义 WooCommerce 可用性文本
- python - Python 从 .csv 文件写入 SQL 数据
- java - 单击按钮时更改文本标签会启动将 xml 转换为 csv 文件的过程?
- apache-kafka - 使用 MongoSinkConnector 删除文档