Using C++26 reflection to design a concept to check, by name, if a class has a given member function

1 week ago 4
ARTICLE AD BOX

My goal is to have a trait or concept that could be called like that: has_member_function_named<X, "foo", int, double>.
My expectation would be that it is true if X has the member function int foo(double), false otherwise.

If foo is hard-coded inside the trait, it is well known and passing the name as an argument could be achieve, pre-C++26, through a straightforward macro.

Yet I'd like to experiment a bit with C++26 reflection and tried to achieve my goal, using this new possibility:

#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

I expected the assertion to pass but it fails and I don't get why:

error: static assertion failed due to requirement 'has_member_function_named<X, operator""_ls<LiteralString<4>{"foo"}>(), int, double>'

What is the issue and how can I fix it?

Notes:

LiteralString is merely used to pass a string literal as constant template parameter. I'm using an immediately called lambda, merely for has_member_function_named to be a concept. The implementation seems straightforward (despite the verbose reflection syntax): for each member of type T, if it's a function (not constructor) named LS with the expected signature, immediately returns true.
Read Entire Article