所以,我正在尝试简化我的泛型类的使用,并遇到了以下想法:
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];
};
另外,我宁愿不让这个类派生自另一个,或完全专门化该类。
答案 0 :(得分:5)
AFAIK你可以这样做,只保留你的语法继承或专业化。
如果你想避免这种情况,你需要更改一下界面。您需要制作x
,y
,z
,t
方法。实际上是方法模板:
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吗?