是否可以使用带有constexpr参数的lambda?是否可以使以下示例正常工作?
下面提供的 ForEach
函数以索引0、1、2,
template <class Func, std::size_t... index>
inline constexpr void ForEach(Func && f, std::index_sequence<index...>)
{
(f(index), ...);
}
template <class Func>
inline constexpr void ForEach(Func && f)
{
ForEach(f, std::make_index_sequence<3>());
}
下面的代码
ForEach([](size_t index)
{
std::cout << index << ' ' << std::endl;
});
输出0、1、2。
但是以下尝试打印元组元素的代码要求index
是constexpr:
auto t = std::make_tuple(1, 2.0, std::string("abc"));
ForEach([&t](size_t index)
{
std::cout << std::get<index>(t) << ' ' << std::endl;
});
,因此无法编译,请参见live example。可以以某种方式使index
constexpr吗?
EDIT1::有一个working example,其中lambda参数用作模板参数:
void Set(Tuple& val, size_t index, Variant const& elem_v)
{
mp_with_index<std::tuple_size_v<Tuple>>(
index,
[&](auto I){
std::visit([&](auto const& alt){
if constexpr (std::is_assignable_v<
std::tuple_element_t<Tuple, I>,
decltype(alt)>)
{
std::get<I>(val) = alt;
} else {
throw /* something */;
}
}, elem_v);
});
}
为什么编译,但是我的示例代码不能编译?
答案 0 :(得分:7)
在此:
ForEach([&t](size_t index)
{
std::cout << std::get<index>(t) << ' ' << std::endl;
});
index
不是常量表达式。这只是一个变量。函数参数不是constexpr。
但是,如果我们对ForEach
进行了一些调整(以与您链接的我的示例相同的方式工作):
template <class Func, std::size_t... index>
inline constexpr void ForEach(Func && f, std::index_sequence<index...>)
{
(f(std::integral_constant<std::size_t, index>()), ...);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// instead of just index
}
ForEach([&t](auto index)
{
std::cout << std::get<index>(t) << ' ' << std::endl;
});
然后这行得通,因为index
不再是size_t
,而是各种std::integral_constant<size_t, V>
的{{1}}的不同实例。该类型看起来something like:
V
将template<class T, T v>
struct integral_constant {
static constexpr T value = v;
typedef T value_type;
typedef integral_constant type; // using injected-class-name
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; } //since c++14
};
转换为std::integral_constant<size_t, V>
会调用size_t
,这不涉及从该对象本身读取任何状态(这是一个空类型),因此允许作为常数表达式。
一种不同的查看方式是,我们将值编码为 type (可以作为常量表达式检索)而不是 value (不能)。