利用C++26的反射机制,设计一个概念,用以按名称检查一个类是否具备某个成员函数
我的目标是拥有一个trait(或称作概念),可以这样被称呼:
has_member_function_named<X, "foo", int, double>。
我的预期是:如果 X 拥有名为 int foo(double) 的成员函数,则为真;否则为假。
如果 foo 被硬编码在trait内,这点众所周知;在C++26之前,通过把名称作为参数传递,可以通过一个简单直接的宏来实现。
不过我想对C++26的反射稍作尝试,并利用这个新特性来实现我的目标:
#include <meta>
#include <string_view>
// LiteralString is a literal class type, usable as constant template parameter
template <std::size_t N>
struct LiteralString {
consteval LiteralString(const char (&s)[N]) {
std::copy(s, s + N, &data[0]);
}
consteval operator std::string_view() const { return {data, data + N - 1}; }
static constexpr std::size_t size = N;
char data[N]{};
};
template <LiteralString LS>
constexpr auto operator""_ls() {
return LS;
}
template <typename T, LiteralString LS, typename out, typename... in>
concept has_member_function_named = []() {
auto members =
std::meta::members_of(^^T, std::meta::access_context::current());
for (auto mem : members) {
if (!std::meta::is_function(mem)) continue;
// Need to check has_identifier, otherwise I've got issues with
// constructors
if (std::meta::has_identifier(mem) &&
(std::meta::identifier_of(mem) != std::string_view(LS)))
continue;
if (std::meta::has_identifier(mem)) {
using Sig = out(in...);
if (std::meta::type_of(mem) == ^^Sig) return true;
}
}
return false;
}();
struct X {
int foo(double);
};
static_assert(has_member_function_named<X, "foo"_ls, int, double>);
我期望断言能通过,但它失败了,我也不明白为什么:
error: static assertion failed due to requirement 'has_member_function_named<X, operator""_ls<LiteralString<4>{"foo"}>(), int, double>'
问题出在哪里?我该如何修复?
注:
* LiteralString 仅用于将字符串字面量作为常量模板参数传递。
* 我使用的是一个立即调用的lambda,纯粹是为了让 has_member_function_named 成为一个概念。
* 实现看起来相当直接(尽管反射语法很冗长):对于类型为 T 的每个成员,如果它是一个名为 LS、签名符合预期的函数(不是构造函数),就立即返回 true。
解决方案
^^Sig 不会给你原始函数类型 out(in...) 的 meta::info,而是它的类型别名。你可以直接提取函数类型 out(in...) 的 info,方法是:
if (std::meta::type_of(mem) == ^^out(in...)) return true;
或者使用 meta::dealias:
using Sig = out(in...);
if (std::meta::type_of(mem) == dealias(^^Sig)) return true;
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。