【问题标题】:Writing a function that detects a generic member编写一个检测泛型成员的函数
【发布时间】:2021-06-12 07:22:43
【问题描述】:

现在可以使用 C++20 编写模板函数 detect_foo,它将返回模板参数是否是具有名为 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 */);

【问题讨论】:

  • 这是不可能的,我不确定你为什么需要它。您可以只使用requires,而不用将其包装在函数中。
  • constexpr auto has_the_member = requires { some_struct.name_of_a_member; };
  • @HolyBlackCat 我关于成员是否在这里的实际业务逻辑比真/假更复杂,我不想为每个成员重复它(例如 N 类型,@987654334 @、BarBaz、可能有 M 个可选字段、namevalueminmax - 我想对 type ⨯ field 产品的每种情况执行相同的逻辑,并且仅编写一次该逻辑,而不是每个字段一次)
  • 我建议将此添加到问题中。
  • 那将违背sscce.org

标签: c++ c++20 c++-concepts


【解决方案1】:

您不需要detect 函数,因为您可以使用requires

有 M 个可选字段...想要执行相同的逻辑...并且只编写一次该逻辑

想到传递“成员名称”的唯一方法是使用返回所述成员的 lambda(或函数):

auto get_foo = [](auto &&obj) -> decltype(decltype(obj)(obj).foo) {return decltype(obj)(obj).foo;};

注意显式指定的返回类型,它为我们提供了 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.`
}

【讨论】:

  • 谢谢!我曾尝试(但失败)了 lambda,因为我缺少 SFINAE 的显式返回类型。
  • 设法删除了 lambda 中的重复名称:[](auto &amp;&amp;obj) -&gt; decltype(decltype(obj)(obj).x, void()) {}
  • @Jean-MichaëlCelerier 是的,但您实际上无法使用此 lambda 访问成员。
猜你喜欢
  • 2017-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多