编写检测泛型成员的函数
Writing a function that detects a generic member
现在使用 C++20 可以编写模板函数 detect_foo
,它将 return 模板参数是否为具有名为 foo
的成员的结构。
示例:
consteval bool detect_foo(auto&& arg) {
if constexpr(requires { arg.foo; }) {
// arg has a "foo" member
return true;
} else {
// arg does not
return false;
}
}
因此,我们在 .
运算符的左侧具有泛型:在 arg.foo
中,arg
可以是泛型。
我的问题是:如何使 foo
部分通用,例如我们有没有一种非宏的方法来编写一个 detect
函数,它的 API 离这个不远:
bool has_the_member = detect(some_struct, name_of_a_member);
例如
struct foo { int value; } a_foo;
struct bar { int value; } a_bar;
detect(a_foo, /* some magic incantation to refer to "value" */);
detect(a_bar, /* should be the same incantation than for a_foo */);
您不需要 detect
函数,因为您可以只使用 requires
.
have M optional fields ... want to perform the same logic ... and only write that logic once
想到的传递“成员名称”的唯一方法是使用 returns 表示成员的 lambda(或函数):
auto get_foo = [](auto &&obj) -> decltype(decltype(obj)(obj).foo) {return decltype(obj)(obj).foo;};
注意明确指定的 return 类型,这给了我们 SFINAE。
请注意,您必须重复成员名称两次。这需要一个宏来生成那些 lambda。
您仍然不需要 detect
函数,并且可以直接在您的代码中将 requires
与 lambda 一起使用。示例:
void print_member(const auto &obj, auto member)
{
if constexpr (requires{member(obj);})
std::cout << member(obj) << '\n';
else
std::cout << "No such member.\n";
}
struct A {int foo = 1;};
struct B {int bar = 1;};
int main()
{
print_member(A{}, get_foo); // `1`
print_member(B{}, get_foo); // `No such member.`
}
现在使用 C++20 可以编写模板函数 detect_foo
,它将 return 模板参数是否为具有名为 foo
的成员的结构。
示例:
consteval bool detect_foo(auto&& arg) {
if constexpr(requires { arg.foo; }) {
// arg has a "foo" member
return true;
} else {
// arg does not
return false;
}
}
因此,我们在 .
运算符的左侧具有泛型:在 arg.foo
中,arg
可以是泛型。
我的问题是:如何使 foo
部分通用,例如我们有没有一种非宏的方法来编写一个 detect
函数,它的 API 离这个不远:
bool has_the_member = detect(some_struct, name_of_a_member);
例如
struct foo { int value; } a_foo;
struct bar { int value; } a_bar;
detect(a_foo, /* some magic incantation to refer to "value" */);
detect(a_bar, /* should be the same incantation than for a_foo */);
您不需要 detect
函数,因为您可以只使用 requires
.
have M optional fields ... want to perform the same logic ... and only write that logic once
想到的传递“成员名称”的唯一方法是使用 returns 表示成员的 lambda(或函数):
auto get_foo = [](auto &&obj) -> decltype(decltype(obj)(obj).foo) {return decltype(obj)(obj).foo;};
注意明确指定的 return 类型,这给了我们 SFINAE。
请注意,您必须重复成员名称两次。这需要一个宏来生成那些 lambda。
您仍然不需要 detect
函数,并且可以直接在您的代码中将 requires
与 lambda 一起使用。示例:
void print_member(const auto &obj, auto member)
{
if constexpr (requires{member(obj);})
std::cout << member(obj) << '\n';
else
std::cout << "No such member.\n";
}
struct A {int foo = 1;};
struct B {int bar = 1;};
int main()
{
print_member(A{}, get_foo); // `1`
print_member(B{}, get_foo); // `No such member.`
}