根据模板参数条件C ++ 17创建成员别名

时间:2018-01-23 14:32:52

标签: c++ templates variables metaprogramming alias

所以,我正在尝试简化我的泛型类的使用,并遇到了以下想法:

给出了以下结构:

template <size_t size>
struct Vector {
    std::array<float, size> data;

    float& x = data[0];
    float& y = data[1]; // Declare y only if size is > 0
    float& z = data[2]; // Declare z only if size is > 1
    float& w = data[3]; // Declare w only if size is > 2
};

显然,如果我尝试像这样运行程序,那么数组会抛出超出范围的异常。

现在有办法只在条件(在编译时知道)给出这些别名吗?

我想到了std :: enable_if:

的方式
template <size_t size>
struct Vector {
    std::array<float, size> data;

    float& x = data[0];
    declare_if<(size > 0), float&> y = data[1];
    declare_if<(size > 1), float&> z = data[2];
    declare_if<(size > 2), float&> w = data[3];
};

另外,我宁愿不让这个类派生自另一个,或完全专门化该类。

6 个答案:

答案 0 :(得分:5)

AFAIK你可以这样做,只保留你的语法继承或专业化。

如果你想避免这种情况,你需要更改一下界面。您需要制作xyzt方法。实际上是方法模板:

template <size_t size>
struct Vector {
    std::array<int, size> data;

    template <std::size_t S = size, class = std::enable_if_t<(S > 0)>>
    auto x() -> int& { return data[0]; };

    template <std::size_t S = size, class = std::enable_if_t<(S > 1)>>
    auto y() -> int& { return data[1]; };

    template <std::size_t S = size, class = std::enable_if_t<(S > 2)>>
    auto z() -> int& { return data[2]; };

    template <std::size_t S = size, class = std::enable_if_t<(S > 3)>>
    auto t() -> int& { return data[3]; };  
};
Vector<2> v;

v.x();
v.y();
v.z(); // error: no matching member function for call to 'z'

答案 1 :(得分:2)

最有可能采取专业化:

template <size_t size>
class Vector {
    std::array<float, size> data;

    float& x = data[0];
    float& y = data[1]; // Declare y only if size is > 1
    float& z = data[2]; // Declare z only if size is > 2
    float& w = data[3]; // Declare w only if size is > 3
};
template<> class Vector<0> {
    std::array<float, 0> data;
};
template<> class Vector<1> {
    std::array<float, 1> data;
    float &x = data[0];
};

(请注意,我已将注释中的大小限制更改为不超过数组的范围。)

此外,如果您不喜欢完全专业化的想法,那么,无论如何,您都需要在通用案例中引入这些成员,但他们的默认绑定可能会发生变化:

template <size_t size>
class Vector {
    std::array<float, size> data;

    float& x = data[0];
    float& y = data[std::min(size - 1, 1)];
    float& z = data[std::min(size - 1, 2)];
    float& w = data[std::min(size - 1, 3)];
};

(如果您对x,y,z和w引用相同的数组元素感到满意。)

答案 2 :(得分:1)

我建议与创建引用其他成员的成员略有不同(如果您希望可以分配类,则必须为每个成员手动实现赋值运算符)。

为什么不能为您访问某些免费功能?

template <std::size_t i, std::size_t size>
auto & get(Vector<size> & v) { return std::get<i>(v.data); }

template <std::size_t size>
auto & x(Vector<size> & v) { return get<0>(v.data); }

template <std::size_t size>
auto & y(Vector<size> & v) { return get<1>(v.data); }

//...

如果您尝试访问大小不足的向量中的成员

,这将产生编译时错误

答案 3 :(得分:1)

如果有函数返回引用而不是引用公共成员是一个选项,您可以使用:

layout_weight

答案 4 :(得分:0)

我同意其他建议使用函数而不是访问引用的答案。到目前为止未提及的一个原因是,对于引用,您无法对数据强制执行const:const对象中的float&仍然可以修改,即使它引用了const成员变量。从您的代码派生的示例:

#include <iostream>

template <size_t size>
struct Vector {

  Vector() { std::fill(data, data + 4, 0.0f); }

  float data[4];

  float& x = data[0];
  float& y = data[1]; 
  float& z = data[2]; 
  float& w = data[3]; 

  // read-write access
  float& getx() { return data[0]; }
};

int main()
{
  const Vector<4> v;

  //++v.data[0]; // compile error

  std::cout << v.x << std::endl;
  ++v.x; // modifies const through non-const ref!
  std::cout << v.x << std::endl;

  //++v.getx(); // compile error (member function enforces const)

}

答案 5 :(得分:-2)

为什么不声明一个函数模板float&amp; get()你可以根据大小std :: enable_if吗?