使用结构复制构造进行聚合初始化

问题描述 投票:0回答:1

有没有办法在 C++ 中模仿 Kotlin 的数据类“copy()”?
这允许复制对象并在单个表达式中修改其特定部分,请参阅 Kotlin 示例:

data class SomeData(val a: Int, val b: String)
...
SomeData(a = 10, b = "10").copy(b = "ten")

在 C++20 中我可以做

struct SomeData {
    int a;
    string b;
};
...
SomeData sd1 = { .a = 10, .b = "10" };
SomeData sd2 = { .a = sd1.a, .b = "ten" };

但是当结构变得越来越大时,这会变得非常笨重和不安全。

我正在考虑编写自己的函数,该函数将充当复制构造函数,但也需要

std::initializer_list
在复制的对象上应用指定的初始化。

  1. 是否有任何语言支持我可以利用,或者我只剩下自己的功能?
    注意:我无法使用C++23
  2. 对我自己的功能实现有什么建议吗?
kotlin struct c++20 initializer-list data-class
1个回答
0
投票

我以为这最终会不那么笨重,但最终我不太确定。无论如何,至少这是一种强调“指定您想要更改的成员”语义的替代方案,而不是一个具有“指定您想要保留更改的成员”语义的列表。

您可以利用可变参数自动非类型模板参数,并将指向成员的指针作为参数,来指定您想要替换修改副本中的哪些成员及其新值:

namespace detail {

// Helper trait to get underlying type of member from pointer-to-member.
template <typename T> struct ptr_to_member_underlying;

template <typename ClassType, typename MemberType>
struct ptr_to_member_underlying<MemberType ClassType::*> {
  using type = MemberType;
};

template <typename T>
using ptr_to_member_underlying_t = typename ptr_to_member_underlying<T>::type;

template <typename T, auto mem_ref, typename V>
void assignMember(T &t, V &&mem_value) {
  t.*mem_ref = std::forward<V>(mem_value);
}

} // namespace detail

/// @tparam mem_refs        Pointer-to-members for the public data members of
///                         `t`that should be modified in the copy.
/// @param  new_mem_values  New values for these modified data members.
template <auto... mem_refs, typename T>
T modifiedCopy(T const &t,
               detail::ptr_to_member_underlying_t<decltype(mem_refs)>
                   &&... new_mem_values) {
  auto tc = t;
  (detail::assignMember<T, mem_refs>(
       tc, std::forward<detail::ptr_to_member_underlying_t<decltype(mem_refs)>>(
               new_mem_values)),
   ...);
  return tc;
}

int main() {
  SomeData sd1{.a = 10, .b = "10"};
  auto sd2 = modifiedCopy<&SomeData::b>(sd1, "ten");
}

您可以使用宏来简化此操作,但需要考虑使用宏的普遍问题。

© www.soinside.com 2019 - 2024. All rights reserved.