根据模板参数条件创建成员别名 C++17
Create member alias based on a template parameter condition C++17
所以,我试图简化我的通用 classes 的使用,并想到了以下想法:
给出以下结构:
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];
};
此外,我 不希望 让 class 从另一个派生,或者完全专门化 class。
最有可能的是求助于专业化:
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 指的是同一个数组元素。)
为什么不声明一个函数模板 float& get() ,你可以 std::enable_if 基于大小?
据我所知,您可以做到这一点,并且仅通过继承或专门化来保留您的语法。
如果你想避免这种情况,你需要稍微改变一下界面。您需要创建 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'
我建议采用与创建引用其他成员的成员略有不同的方法(如果您希望 class 可赋值,则必须为每个成员手动实现赋值运算符)。
为什么不用一些免费的功能来为您访问?
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); }
//...
如果您尝试访问大小不足的向量中的成员,这将产生编译时错误
如果函数返回引用而不是引用 public 成员是一个选项,您可以选择:
#include <array>
#include <type_traits>
template<size_t size>
struct Vector
{
std::array<float, size> data;
template<size_t s = size, std::enable_if_t<s >= 1, int> = 0> float& x() { return data[0]; }
template<size_t s = size, std::enable_if_t<s >= 2, int> = 0> float& y() { return data[1]; }
template<size_t s = size, std::enable_if_t<s >= 3, int> = 0> float& z() { return data[2]; }
template<size_t s = size, std::enable_if_t<s >= 4, int> = 0> float& w() { return data[3]; }
};
我同意建议使用函数而不是访问引用的其他答案。到目前为止没有提到的一个原因是,对于引用,您不能对数据强制执行常量: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)
}
所以,我试图简化我的通用 classes 的使用,并想到了以下想法:
给出以下结构:
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];
};
此外,我 不希望 让 class 从另一个派生,或者完全专门化 class。
最有可能的是求助于专业化:
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 指的是同一个数组元素。)
为什么不声明一个函数模板 float& get() ,你可以 std::enable_if 基于大小?
据我所知,您可以做到这一点,并且仅通过继承或专门化来保留您的语法。
如果你想避免这种情况,你需要稍微改变一下界面。您需要创建 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'
我建议采用与创建引用其他成员的成员略有不同的方法(如果您希望 class 可赋值,则必须为每个成员手动实现赋值运算符)。
为什么不用一些免费的功能来为您访问?
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); }
//...
如果您尝试访问大小不足的向量中的成员,这将产生编译时错误
如果函数返回引用而不是引用 public 成员是一个选项,您可以选择:
#include <array>
#include <type_traits>
template<size_t size>
struct Vector
{
std::array<float, size> data;
template<size_t s = size, std::enable_if_t<s >= 1, int> = 0> float& x() { return data[0]; }
template<size_t s = size, std::enable_if_t<s >= 2, int> = 0> float& y() { return data[1]; }
template<size_t s = size, std::enable_if_t<s >= 3, int> = 0> float& z() { return data[2]; }
template<size_t s = size, std::enable_if_t<s >= 4, int> = 0> float& w() { return data[3]; }
};
我同意建议使用函数而不是访问引用的其他答案。到目前为止没有提到的一个原因是,对于引用,您不能对数据强制执行常量: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)
}