Mat*_*vel 7 c++ lambda metaprogramming boost-hana c++17
我正在尝试使用嵌套的constexpr lambdas创建一个curried接口,但编译器不认为它是一个常量表达式.
namespace hana = boost::hana;
using namespace hana::literals;
struct C1 {};
template < typename T,
std::size_t size >
struct Array {};
constexpr auto array_ = [] (auto size) {
return [=] (auto type) {
return hana::type_c<Array<typename decltype(type)::type, size()>>;
};
};
int main() {
constexpr auto c1 = hana::type_c<C1>;
constexpr auto test = hana::type_c<Array<typename decltype(c1)::type, hana::size_c<100>()>>;
constexpr auto test2 = array_(hana::size_c<100>)(c1);
}
Run Code Online (Sandbox Code Playgroud)
我之前发布了一个问题,因为我找到了一个不同的最小例子,但这还不够.
错误:
test2.cpp: In instantiation of ‘<lambda(auto:1)>::<lambda(auto:2)> [with auto:2 = boost::hana::type_impl<C1>::_; auto:1 = boost::hana::integral_constant<long unsigned int, 100>]’:
test2.cpp:31:54: required from here
test2.cpp:20:16: error: ‘__closure’ is not a constant expression
return hana::type_c<Array<typename decltype(type)::type, size()>>;
^~~~
test2.cpp:20:16: note: in template argument for type ‘long unsigned int’
test2.cpp: In function ‘int main()’:
test2.cpp:31:18: error: ‘constexpr const void test2’ has incomplete type
constexpr auto test2 = array_(hana::size_c<100>)(c1);
Run Code Online (Sandbox Code Playgroud)
__closure is not a constant expression:如果有人能解释我这个错误,那将是一个很大的帮助.我之前遇到过这个错误,但不记得为什么.
我将您的测试用例缩减为:
#include <type_traits>
constexpr auto f = [](auto size) {
return [=](){
constexpr auto s = size();
return 1;
};
};
static_assert(f(std::integral_constant<int, 100>{})(), "");
int main() { }
Run Code Online (Sandbox Code Playgroud)
如上面的评论所述,这size是因为不是函数体内的常量表达式.这不是Hana特有的.作为一种解决方法,您可以使用
constexpr auto f = [](auto size) {
return [=](){
constexpr auto s = decltype(size)::value;
return 1;
};
};
Run Code Online (Sandbox Code Playgroud)
或类似的东西.
问题是你试图在模板非类型参数中使用lambda捕获的变量之一.
return hana::type_c<Array<typename decltype(type)::type, size()>>;
// ^~~~
Run Code Online (Sandbox Code Playgroud)
模板非类型参数必须是常量表达式.在lambda中,你不能在常量表达式中使用捕获的变量.lambda constexpr是否无关紧要.
但是你可以在常量表达式中使用普通变量,即使它们不是constexpr变量.例如,这是合法的:
std::integral_constant<int, 100> i; // i is not constexpr
std::array<int, i()> a; // using i in a constant expression
Run Code Online (Sandbox Code Playgroud)
那么为什么我们不能在常量表达式中使用捕获的变量呢?我不知道这条规则的动机,但这里有标准:
[expr.const]
(2)条件表达式是一个核心常量表达式,除非在lambda表达式中有...(2.11),
this对变量的引用或者自变存储持续时间在lambda表达式之外定义,其中引用将是一种使用感.
CWG1613可能会有一些线索.
如果我们要将内部lambda重写为命名类,我们会有一个不同但相关的问题:
template <typename T>
struct Closure {
T size;
constexpr Closure(T size_) : size(size_) {}
template <typename U>
constexpr auto operator()(U type) const {
return hana::type_c<Array<typename decltype(type)::type, size()>>;
}
};
constexpr auto array_ = [] (auto size) {
return Closure { size };
};
Run Code Online (Sandbox Code Playgroud)
现在错误将是this在模板非类型参数中隐式使用指针.
return hana::type_c<Array<typename decltype(type)::type, size()>>;
// ^~~~~
Run Code Online (Sandbox Code Playgroud)
我宣称它是一致性Closure::operator()()的constexpr函数,但这并不重要.该this指针是被禁止的常量表达式([expr.const]2.1)的使用.声明的函数constexpr没有特别的规定来放宽可能出现在它们中的常量表达式的规则.
现在原始错误更有意义,因为捕获的变量被转换为lambda闭包类型的数据成员,因此使用捕获的变量有点像通过lambda自己的" this指针"进行间接.
这是一种解决方法,它引入了对代码的最少更改:
constexpr auto array_ = [] (auto size) {
return [=] (auto type) {
const auto size_ = size;
return hana::type_c<Array<typename decltype(type)::type, size_()>>;
};
};
Run Code Online (Sandbox Code Playgroud)
现在我们使用常量表达式之外的捕获变量来初始化一个普通变量,然后我们可以在模板非类型参数中使用它.
此答案已被编辑几次,因此以下评论可能会参考以前的修订版.
| 归档时间: |
|
| 查看次数: |
982 次 |
| 最近记录: |