【问题标题】:Is there a generic way to make a tuple out of all class attributes?有没有一种通用的方法可以从所有类属性中创建一个元组?
【发布时间】:2020-11-07 17:05:32
【问题描述】:

我有许多类使用std::tie 从所有类属性中创建一个元组,并使用它来实现== 运算符。它们看起来像这样:

class S
{
    int number;
    std::string text;
    // and many other attributes...
    
    auto tied() const noexcept { return std::tie(/* list all attributes here */); }
    
    bool operator==(const S &o) const noexcept
    {
        return tied() == o.tied();
    }
};

这些类具有相似的方法,但属性非常不同,所以我想创建一个它们都继承自的基类,并且我想在基类中包含这一点比较。

但是,由于我无法定义返回 autovirtual 方法,因此我正在努力编写一个抽象的泛型 tied() 方法,该方法应该从所有派生类的属性中生成一个元组,无论有多少它们或它们的类型。

这可行吗?

注意:所有属性都是普通类型或std::strings。

【问题讨论】:

  • 不,这不可行。这听起来像是一个 XY 问题。您要解决的真正问题是什么?不,不是关于从班级成员制作元组的问题,而是您认为解决方案是从班级成员制作元组的问题,所以这就是您要问的问题。也许如果你解释你原来的问题,一个不同的解决方案就会变得非常明显。
  • 如果您可以使用 C++20,那么可用于 operator==default 可能就是您正在寻找的。​​span>
  • 有“黑客”,比如 stackoverflow.com/q/39768517/1774667 ,但不是一般的。孩子们必须自己做这项工作来添加他们的方法。如前所述,operator==(...) = default 可能会做你想做的事。
  • 与 python 不同,C++ 没有属性接口 (stackoverflow.com/questions/9058305/…)。 C++ 将承担更多的责任来实现这一点 - 它不是该语言的目标解决方案。
  • @SamVarshavchik 我有十几个具有相同模式的类:许多不同的属性和一个 == 运算符。这些类的对象代表参数集,当发生完全更新时,我只对至少一个参数已更改的对象感兴趣,因此进行比较。我正在尝试找到一种快速的方法来实现这一点,如果将来我需要添加一组新参数,我将只创建一个新类,其中所有新参数作为属性。然后从给我相同的比较机制的基类继承。

标签: c++


【解决方案1】:

有没有一种通用的方法可以从所有类属性中创建一个元组?

无法生成成员列表。这是一种语言特性,它需要比 C++ 更多的反射能力。充其量你可以拥有一个同时生成成员声明和生成元组的函数的宏。有关该想法的实现,请参阅 Boost Fusion。

当然,您不仅限于使用 C 预处理器进行元编程。如果您不介意使构建过程复杂化,您可以使用任何语言生成 C++ 源代码。

我正在努力写一个抽象的泛型tie()

没有办法编写一个会为派生实例返回不同元组的虚拟成员函数。

这可行吗?

没有。

并使用它来实现 == 运算符。

从 C++20 开始,您可以使用默认的<=> 来生成所有比较运算符。在此之前,您需要样板。

【讨论】:

  • 比目前拥有的更多; C++23 是(敲木头)添加编译时反射。
  • 感谢您的回答。 C++20 默认比较运算符在这里可以帮助我,但我坚持使用 C++14
【解决方案2】:

如果元素数量有限,可以使用 CRTP 和https://stackoverflow.com/a/39779537/1774667 来查找元素数量。

使用结构化绑定,您可以使用它们构建一个元组。

这可以写在 CRTP 库中。

template<class T>
struct implement_equals {
  friend bool operator!=(implement_equals const& lhs, implement_equals const& rhs ) {
    return !(lhs==rhs);
  }
  T const& self() const {
    return *static_cast<T const*>(this);
  }
  friend bool operator==(implement_equals const& lhs, implement_equals const& rhs) {
    constexpr std::size_t count = construct_airity<T>;
    return make_tie_from<count>{}(lhs.self()) == make_tie_from<count>{}(rhs.self());
  }
};

接下来写make_tuple_from

template<std::size_t>
struct make_tie_from;

template<>
struct make_tie_from<1> {
  template<class T>
  auto operator()( T const& t ) const {
    auto const&[e0] = t;
    return std::tie(e0);
  }
};

然后写出其中的 20 个。

有些库已经为您执行此操作,您可以通过谷歌搜索找到。它们都不是完美的,它们都要求您公开公开数据。

如果您想隐藏该数据,请创建一个包含公开数据的结构以获得平局,并公开某种方式让 implement_equals 访问该结构(朋友,随便)。


中,您甚至无法进行这种残废的反思。

你可以写implement_equals,但你必须手动写领带。但是,它比虚函数要好。

【讨论】:

    猜你喜欢
    • 2014-03-25
    • 2021-08-14
    • 1970-01-01
    • 2021-06-16
    • 2013-01-09
    • 1970-01-01
    • 2016-08-13
    • 1970-01-01
    • 2021-12-17
    相关资源
    最近更新 更多