c++ - 类模板中的多个可选成员,无需开销

标签 c++ templates optional-parameters

如果我想要一个带有可选成员的类,我正在使用模板特化:

template<class T>
struct X {
  T t;
  void print() { cout << "t is " << t << '\n'; }
};
template<>
struct X<void> {
  void print() { cout << "without T\n"; }
};

这很好,因为没有运行时开销和很少的代码重复。 但是,如果我有 3 个而不是 1 个可选类成员,我必须编写 2^3=8 个类,即“小重复”很快变得不合理。

一个可能的解决方案可能是像这样使用 std::conditional:

template<class T1, class T2, class T3>
struct X {
  conditional_t<is_void_v<T1>, char, T1> t1;
  conditional_t<is_void_v<T2>, char, T2> t2;
  conditional_t<is_void_v<T3>, char, T3> t3;

  void print() {
    if constexpr (!is_void_v<T1>) cout << "t1 is " << t1 << '\n';
    if constexpr (!is_void_v<T2>) cout << "t2 is " << t2 << '\n';
    if constexpr (!is_void_v<T3>) cout << "t3 is " << t3 << '\n';
  }
};

但是现在,我类(class)的对象会浪费内存。我正在寻找某种方法来避免大部分代码重复(在可选成员代码开销的数量上最多呈线性),同时避免花费不必要的运行时间和内存。

请注意,对于单个可选类成员(请参阅 Optional class members without runtime overheadMost efficient way to implement template-based optional class members in C++? )存在此问题(有答案),但据我所知,对于多个可选成员尚未回答。

最佳答案

使用 optional_member 类,

template <class T>
struct OptionalMember
{
    T t;
    static constexpr bool has_member = true;
};

template<> struct X<void>
{
    static constexpr bool has_member = false;
};

您可以使用继承(只要它们的类型不同)和 EBO 来避免额外的内存。

template<class T1, class T2, class T3>
struct X : OptionalMember<T1>, OptionalMember<T2>, OptionalMember<T3>
{
  void print() {
    if constexpr (!OptionalMember<T1>::has_member)
        cout << "t1 is " << OptionalMember<T1>::t << '\n';
    if constexpr (!OptionalMember<T2>::has_member)
        cout << "t2 is " << OptionalMember<T2>::t << '\n';
    if constexpr (!OptionalMember<T1>::has_member)
        cout << "t3 is " << OptionalMember<T3>::t << '\n';
  }
};

或者,从 C++20 开始,属性 [[no_unique_address]] (只要它们的类型不同,就没有额外的内存)。

template<class T1, class T2, class T3>
struct X {
  [[no_unique_address]] OptionalMember<T1> t1;
  [[no_unique_address]] OptionalMember<T2> t2;
  [[no_unique_address]] OptionalMember<T3> t3;

  void print() {
    if constexpr (!t1.has_member) cout << "t1 is " << t1.t << '\n';
    if constexpr (!t2.has_member) cout << "t2 is " << t2.t << '\n';
    if constexpr (!t3.has_member) cout << "t3 is " << t3.t << '\n';
  }
};

如果类型可能相同,您可以修改 OptionalMember采取额外的标签(或任何类型的标识符作为 std::size_t ):

template <class T, class Tag>
struct OptionalMember
{
    T t;
    static constexpr bool has_member = true;
};

template<class Tag> struct X<void, Tag>
{
    static constexpr bool has_member = false;
};

然后

struct tag1;
struct tag2;
struct tag3;

并使用 OptionalMember<TX, tagX>而不是 OptionalMember<TX>从上面的解决方案。

关于c++ - 类模板中的多个可选成员,无需开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69222391/

相关文章:

c++ - 覆盖基模板类方法

common-lisp - 区分具有默认值的 &optional 参数和无值

wolfram-mathematica - 我如何获得相互依赖的选项?

dictionary - 在 Dart 中使用 ifAbsent 映射更新方法

c++ - 模板参数替换失败,C 字符串作为非类型模板参数

c++ - 了解 OpenGL 中的绑定(bind)/激活纹理性能损失

c++ - 如何监控放入标准输出缓冲区的内容并在特定字符串存放在管道中时中断?

email - 如何在 salesforce.com 中配置有关新案例评论的电子邮件通知?

c++ - 最小/最大整数和 double

c++ - 如何继承模板函数?