C++(不知何故)将struct限制为父联合大小

Pre*_*sor 6 c++ unions bit-fields

我正在尝试创建一个可变大小的颜色类 - 给定模板确定的值数组,我想为数组中的每个值创建命名别名,即:

template<int C = 3, typename T = unsigned char>
class Color {
public:
  union {
    T v[C];
    struct {
      T r, g, b, a;
    };
  };
};
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试为C = 3使用相同的类,则union要求4字节的大小('a'成员).或者,使用数学表达的位域大小((名为a,anonymous T成员的结构,大小在C> 3时评估为1),编译器发出一个允许警告(不可抑制,根据In gcc,如何静音 -敏感警告?),不适合大规模API的东西.

我如何允许单个类处理不同数量的变量,同时保留每个变量名称而不实现递归包含宏魔法(试过这个,不应该).提前致谢!

编辑:为了澄清问题,以下任何一个答案将解决此问题:

  • 抑制GCC的-perpermissive错误(忽略#pragma诊断不适用于许可)
  • 设置union或child struct的最大大小不超过C字节
  • 对于C字节未覆盖的成员,允许位域长度为0(GCC允许数据表达式用于位域长度,例如(C-3> 0)?8:0;)
  • 通过其他方式禁用C字节未涵盖的成员(即神话static_if())

Vau*_*ato 4

您可以针对 C 的不同情况对该结构进行专门化:

template <int C = 3, typename T = unsigned char> union Color;

template <typename T>
union Color<3,T> {
  T v[3];
  struct {
    T r,g,b;
  };
};

template <typename T>
union Color<4,T> {
  T v[4];
  struct {
    T r,g,b,a;
  };
};
Run Code Online (Sandbox Code Playgroud)

请注意,匿名结构是非标准的。

如果可以使用成员函数,我认为这将是更好的方法:

template <int C,typename T>
class Color {
  public:
    using Values = T[C];

    Values &v() { return v_; }

    const Values &v() const { return v_; }

    T& r() { return v_[0]; }
    T& g() { return v_[1]; }
    T& b() { return v_[2]; }

    template <int C2 = C,
      typename = typename std::enable_if<(C2>3)>::type>
    T& a()
    {
      return v_[3];
    }

    const T& r() const { return v_[0]; }
    const T& g() const { return v_[1]; }
    const T& b() const { return v_[2]; }

    template <int C2 = C,
      typename = typename std::enable_if<(C2>3)>::type>
    const T& a() const
    {
      return v_[3];
    }

  private:
    Values v_;
};
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

int main()
{
  Color<3,int> c3;
  Color<4,int> c4;

  c3.v()[0] = 1;
  c3.v()[1] = 2;
  c3.v()[2] = 3;

  std::cout <<
    c3.r() << "," <<
    c3.g() <<"," <<
    c3.b() << "\n";

  c4.v()[0] = 1;
  c4.v()[1] = 2;
  c4.v()[2] = 3;
  c4.v()[3] = 4;

  std::cout <<
    c4.r() << "," <<
    c4.g() << "," <<
    c4.b() << "," <<
    c4.a() << "\n";
}
Run Code Online (Sandbox Code Playgroud)