有没有办法将 `constexpr` 值传递给 lambda,以便它在该 lambda 中保留 `constexpr`?
Is there a way to pass a `constexpr` value into lambda so that it remains `constexpr` inside that lambda?
这是我想做的;发布整个代码,因为它不是太长,并且还可以演示我要解决的具体任务。基本上,我需要一种方法来按索引迭代参数包中的值(索引部分很重要,即使在本例中不需要)。
#include <iostream>
#include <tuple>
#include <type_traits>
template <int First, int Last, typename Functor>
constexpr void static_for(Functor&& f)
{
if constexpr (First < Last)
{
f(std::integral_constant<int, First>{});
static_for<First + 1, Last, Functor>(std::forward<Functor>(f));
}
}
template <size_t index, typename... Args>
auto value_by_index(Args&&... args) noexcept {
return std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...));
}
template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
static_for<0, sizeof...(ValueTypes)>([&](int i) {
auto v = value_by_index<static_cast<size_t>(i), ValueTypes...>(values...);
std::cout << v << std::endl;
});
}
int main()
{
traverse(0.0f, 1, 3.33, "str");
return 0;
}
编译错误当然是:
<source>:24:71: error: 'i' is not a constant expression
如果 lambdas 可以有明确的模板参数,i
就是这样一个参数,编译器很明显它在编译时是已知的。但这不是 lambda 的工作方式。
如果您想将其视为 X-Y 问题,我想我不需要在 static_for
中特别调用 lambda,但我确实需要调用一些可以访问参数的代码按索引打包 traverse
,如果 traverse
是成员函数,我需要访问它的 this
.
使用通用的 lambda 和 constexpr 转换运算符c++17:
template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
static_for<0, sizeof...(ValueTypes)>([&](auto I)
// ~~~^
{
auto v = value_by_index<I>(values...);
// ~^~
std::cout << v << std::endl;
});
}
为 lambda 表达式使用模板参数列表 c++20:
template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
static_for<0, sizeof...(ValueTypes)>([&]<int I>(std::integral_constant<int, I>)
// ~~~~^ ~^~
{
auto v = value_by_index<I>(values...);
// ~^~
std::cout << v << std::endl;
});
}
来不及玩了?
Basically, I need a way to iterate values from parameter pack by index (the index part is important, even though it's not required in this example).
抱歉,但是...std::make_index_sequence
和 std::index_sequence
的旧用法怎么样?
维护您的 value_by_index()
,我提出以下基于 traverse()
和 traverse_helper()
的 C++14 解决方案
template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
{
using unused = int[];
(void)unused { 0, (f(value_by_index<Is>(vs...)), 0)... };
}
template <typename F, typename ... VTs>
void traverse (F f, VTs ... vs)
{ traverse_helper(f, std::make_index_sequence<sizeof...(VTs)>{}, vs...); }
请注意,我还传递了可调用参数。
如果你可以使用 C++17(如你标记的那样),traverse_helper()
就变成了
template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
{ (f(value_by_index<Is>(vs...)), ...); }
您可以调用traverse()
如下
traverse([](auto x){ std::cout << x << std::endl; },
0.0f, 1, 3.33, "str");
下面是完整的C++14编译示例
#include <iostream>
#include <tuple>
#include <type_traits>
template <std::size_t I, typename ... As>
auto value_by_index (As && ... as) noexcept
{ return std::get<I>(std::forward_as_tuple(std::forward<As>(as)...)); }
template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
{
using unused = int[];
(void)unused { 0, (f(value_by_index<Is>(vs...)), 0)... };
}
template <typename F, typename ... VTs>
void traverse (F f, VTs ... vs)
{ traverse_helper(f, std::make_index_sequence<sizeof...(VTs)>{}, vs...); }
int main ()
{
traverse([](auto x){ std::cout << x << std::endl; },
0.0f, 1, 3.33, "str");
}
这是我想做的;发布整个代码,因为它不是太长,并且还可以演示我要解决的具体任务。基本上,我需要一种方法来按索引迭代参数包中的值(索引部分很重要,即使在本例中不需要)。
#include <iostream>
#include <tuple>
#include <type_traits>
template <int First, int Last, typename Functor>
constexpr void static_for(Functor&& f)
{
if constexpr (First < Last)
{
f(std::integral_constant<int, First>{});
static_for<First + 1, Last, Functor>(std::forward<Functor>(f));
}
}
template <size_t index, typename... Args>
auto value_by_index(Args&&... args) noexcept {
return std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...));
}
template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
static_for<0, sizeof...(ValueTypes)>([&](int i) {
auto v = value_by_index<static_cast<size_t>(i), ValueTypes...>(values...);
std::cout << v << std::endl;
});
}
int main()
{
traverse(0.0f, 1, 3.33, "str");
return 0;
}
编译错误当然是:
<source>:24:71: error: 'i' is not a constant expression
如果 lambdas 可以有明确的模板参数,i
就是这样一个参数,编译器很明显它在编译时是已知的。但这不是 lambda 的工作方式。
如果您想将其视为 X-Y 问题,我想我不需要在 static_for
中特别调用 lambda,但我确实需要调用一些可以访问参数的代码按索引打包 traverse
,如果 traverse
是成员函数,我需要访问它的 this
.
使用通用的 lambda 和 constexpr 转换运算符c++17:
template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
static_for<0, sizeof...(ValueTypes)>([&](auto I)
// ~~~^
{
auto v = value_by_index<I>(values...);
// ~^~
std::cout << v << std::endl;
});
}
为 lambda 表达式使用模板参数列表 c++20:
template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
static_for<0, sizeof...(ValueTypes)>([&]<int I>(std::integral_constant<int, I>)
// ~~~~^ ~^~
{
auto v = value_by_index<I>(values...);
// ~^~
std::cout << v << std::endl;
});
}
来不及玩了?
Basically, I need a way to iterate values from parameter pack by index (the index part is important, even though it's not required in this example).
抱歉,但是...std::make_index_sequence
和 std::index_sequence
的旧用法怎么样?
维护您的 value_by_index()
,我提出以下基于 traverse()
和 traverse_helper()
template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
{
using unused = int[];
(void)unused { 0, (f(value_by_index<Is>(vs...)), 0)... };
}
template <typename F, typename ... VTs>
void traverse (F f, VTs ... vs)
{ traverse_helper(f, std::make_index_sequence<sizeof...(VTs)>{}, vs...); }
请注意,我还传递了可调用参数。
如果你可以使用 C++17(如你标记的那样),traverse_helper()
就变成了
template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
{ (f(value_by_index<Is>(vs...)), ...); }
您可以调用traverse()
如下
traverse([](auto x){ std::cout << x << std::endl; },
0.0f, 1, 3.33, "str");
下面是完整的C++14编译示例
#include <iostream>
#include <tuple>
#include <type_traits>
template <std::size_t I, typename ... As>
auto value_by_index (As && ... as) noexcept
{ return std::get<I>(std::forward_as_tuple(std::forward<As>(as)...)); }
template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
{
using unused = int[];
(void)unused { 0, (f(value_by_index<Is>(vs...)), 0)... };
}
template <typename F, typename ... VTs>
void traverse (F f, VTs ... vs)
{ traverse_helper(f, std::make_index_sequence<sizeof...(VTs)>{}, vs...); }
int main ()
{
traverse([](auto x){ std::cout << x << std::endl; },
0.0f, 1, 3.33, "str");
}