利用C++26的反射机制,设计一个概念,用以按名称检查一个类是否具备某个成员函数

编程语言 2026-07-11

我的目标是拥有一个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>);

LIVE

我期望断言能通过,但它失败了,我也不明白为什么:

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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章