consteval auto struct_to_tuple_type(info type) -> info {
return substitute(^std::tuple,
nonstatic_data_members_of(type)
| std::ranges::transform(std::meta::type_of)
| std::ranges::transform(std::meta::remove_cvref)
| std::ranges::to<std::vector>());
}
型 给定像struct S { int a; char& b; };这样的东西,struct_to_tuple_type(^S)将给你一个std::tuple<int, char>的反射。后一个例子在基于类型的反射中也很容易做到,只是你会使用Boost.Mp11等等的mp_transform来代替std::ranges::transform。但它是一个完全不同的子语言-这就是为什么我质疑那篇论文中列出的优点? 这篇论文还指出了count_if是如何不起作用的。这确实是一个人们必须了解的微妙案例:
template <typename T> inline constexpr bool my_trait = /* ... */;
consteval auto num_const(span<info const> some_types) -> bool {
// this one is built-in, so easy
return std::ranges::count_if(some_types, std::meta::is_const);
}
consteval auto num_my_trait(span<info const> some_types) -> bool {
// this one requires this one weird trick
return std::ranges::count_if(some_types, [](std::meta::info type){
// first, we need my_trait<T>, which is a substitute
// then, we need to pull a value out of it, which we need to declare as bool
return value_of<bool>(substitute(^my_trait, {type}));
});
}
1条答案
按热度按时间ao218c7q1#
C委员会上周(2023年11月)在科纳举行了会议,这在第7研究组中进行了讨论。
C26反射的方向在P2996中概述(目前R 0,R1将于下周发布),这是一个基于值的反射。在高级别上:
^e
是e
的反射(可以是类型、模板、命名空间、表达式等),类型为std::meta::info
[: i :]
拼接i
(基本上是反射的逆)。所以[: ^int :]
是int
类型std::meta
命名空间中有一堆函数,它们接受info
或span<info const>
并返回info
或vector<info
>第七研究组一致通过了这个设计,没有兴趣讨论进一步追求反射TS(即基于类型的反射)。
在P2560的一些评论中,我不同意其中的一些观点-特别是基于类型的“优点”是它具有“更好的可用性”,“更容易教”,并且“对泛型编程更友好”的论点。
我只会注意到反射论文中的一个例子,即实现
make_integer_sequence
。这里的目标是make_integer_sequence<int, 5>
示例化integer_sequence<int, 0, 1, 2, 3, 4>
。如何在基于值的反射中实现它?字符串
在这里,
substitute
是一个反射API,它接受模板的反射和一系列参数的反射,并返回该模板示例化的反射。例如,substitute(^std::tuple, {^int, ^char})
给你^std::tuple<int, char>
,除了它让你生活在值域中。你必须学习它是什么,这是真的,但除此之外,这是一个相当简单的算法:你创建了一个vector
,然后你把东西推到它上面。在这种情况下,我们的“东西”是异构的,因为我们有一个类型模板参数和一堆非类型模板参数,这很好,因为std::meta::info
是唯一的类型。你如何在基于类型的方法中实现这一点?基于类型的元编程的问题是它不能真正是命令式的-它必须是函数式的。正如P2560所指出的,拼接确实需要你有一个常量表达式来拼接。这肯定会影响你必须如何编程。但是丰富的API的可用性意味着你可以在值域停留的时间比你想象的要长,这允许你使用标准库的其余部分API来完成你的工作。例如:
型
给定像
struct S { int a; char& b; };
这样的东西,struct_to_tuple_type(^S)
将给你一个std::tuple<int, char>
的反射。后一个例子在基于类型的反射中也很容易做到,只是你会使用Boost.Mp11等等的mp_transform
来代替std::ranges::transform
。但它是一个完全不同的子语言-这就是为什么我质疑那篇论文中列出的优点?这篇论文还指出了
count_if
是如何不起作用的。这确实是一个人们必须了解的微妙案例:型
这篇文章是正确的,这是不一致的-虽然值得注意的是,我们仍然可以使用
count_if
两者,我认为这使得它的方法更友好的泛型编程和更容易教。我们总能想出办法让这一切变得更好。比如:
型
我认为,总的来说,这比基于类型的方法所需要的机器要少。