代码之家  ›  专栏  ›  技术社区  ›  Alexander S

决定模板化类是包含2个变量还是仅包含1个变量

  •  1
  • Alexander S  · 技术社区  · 1 年前

    我想要一个嵌套类 B 其行为如下:

    • 如果 T void 然后 B 只有一个成员字段 sz sizeof(B) == sizeof(sz)

    • 否则 B 具有成员字段 sz 并以某种方式获得 T

    #include <iostream>
    #include <type_traits>
    
    template <typename T>
    class A {
    
      struct B {
        size_t sz;
        
        if (T != void)
        T t;  // declare T field
      };
    
    };
    

    我找到了这个部分解决方案,但它只适用于积分类型,并且在访问时有一些不便 T 数据

    static constexpr bool is_void = std::is_same_v<void, T>;
    using type = std::conditional_t<is_void, bool, T>;
    
    struct B {
      size_t sz;
      type : (is_void ? 0 : sizeof(type));
      // if 'type' has a name, possible CE: Named bit-field has zero width
    };
    

    或者,我们可以使用继承技巧创建类似的东西,但我想找到该语言提供的其他方法(没有样板代码)(~专门为此类情况创建)。

    struct empty_class {};
    struct container { T t; };  // solves (std::is_class_v<T> && !std::is_final_v<T>)
    
    static constexpr bool is_void = std::is_same_v<void, T>;
    using base = std::conditional_t<is_void, empty_class, container>;
    
    struct B : base {
      size_t sz;
    };
    

    潜在地,的专业化 A<void> 可以创建大量样板代码。

    2 回复  |  直到 1 年前
        1
  •  4
  •   Jan Schultke    1 年前

    即使当所有的专业化 A 不是一个可行的选择,你可以专门化绝对需要的部分。 在这里,这两种情况之间的唯一区别是 T t 是否存在。

    方法A-继承

    template <typename T>
    struct maybe {
      T t;
    };
    
    template <>
    struct maybe<void> { };
    
    template <typename T>
    class A {
      struct B : maybe<T> {
        std::size_t sz;
      };
    };
    

    具有类型的基类 maybe<void> 不应将任何内容添加到的大小 B 因为空基类优化。

    方法B- std::conditional_t

    struct empty { };
    
    template <typename T>
    class A {
      struct B : maybe<T> {
        std::size_t sz;
        [[no_unique_address]] std::conditional_t<std::is_same_v<T, void>, empty, T> t;
      };
    };
    

    如果 t 属于类型 empty 然而,它会污染 B 可能不需要 empty t 成员

    方法C-专业化 B

    template <typename T>
    class A {
      struct B {
        std::size_t sz;
        T t;
      };
    };
    
    template <>
    struct A<void>::B {
        std::size_t sz;
    };
    

    这种方法不需要专门化所有 A. ,但所有 B . 在一个更大的例子中,它可能是最多余的,但它是最干净、最简单的。

        2
  •  2
  •   Remy Lebeau    1 年前

    你可以简单地专门化 A 对于 void :

    template <typename T>
    class A {
      struct B {
        size_t sz;
        T t;
      };
    };
    
    template <>
    class A<void> {
      struct B {
        size_t sz;
      };
    };
    

    实例

    A<int>::B b1;
    b1.t // OK, t exists
    
    A<void>::B b2;
    b2.t // error, t does not exist