“这个对象看起来像一个 3D 矢量”的概念
我有一个项目正在使用一些库,其中每个库都定义某种 3D 矢量,作为示例,我使用 SFML的3D向量在代码的某些部分,reactphysicals3d 的 Vector3
以及来自另一个库的另一个 3D 矢量。
现在我需要为每个向量编写叉积和 std::ostream &operator <<
:
constexpr sf::Vector3f cross(const sf::Vector3f &a, const sf::Vector3f &b)
{
return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
std::ostream &operator <<(std::ostream &o, const sf::Vector3f &v)
{
return o << '{' << v.x << ", " << v.y << ", " << v.z << '}';
}
// ... repeat for every 3D vector type
这意味着大量代码重复,所以我改变了方法
template <typename vector3a_t, typename vector3b_t>
constexpr vector3a_t cross(const vector3a_t &a, const vector3b_t &b)
{
return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
: cross
函数希望具有成员 x
、y
和 z
的两种类型,但显然这是不适用的到 std::ostream &operator <<:
template <typename vector3_t>
std::ostream &operator <<(std::ostream &o, const vector3_t &v)
{
return o << '{' << v.x << ", " << v.y << ", " << v.z << '}';
}
因为模板类型 vector3_t
遮蔽了所有内容,所以我想知道是否可以限制函数接受任何符合“<”概念的类型em>应该看起来像一个 3D 矢量”:
template <typename vector_t>
concept vector3_c = requires(vector_t v) { // error: expected unqualified-id
{ std::is_scalar_v<decltype(v.x)> } -> true;
{ std::is_scalar_v<decltype(v.y)> } -> true;
{ std::is_scalar_v<decltype(v.z)> } -> true;
};
template <vector3_c A, vector3_c B>
constexpr decltype(A) cross(const A &a, const B &b)
{
return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
template <vector3_c V>
std::ostream &operator <<(std::ostream &o, const V &v)
{
return o << '{' << v.x << ", " << v.y << ", " << v.z << '}';
}
但这甚至无法编译。这是我第一次尝试概念,我不知道我想做的事情是否可能。
I have a project which is using a few libraries where each one of the libraries define some sort of 3D vector, as an example I use SFML's 3D vector in some parts of the code, reactphysics3d's Vector3
on others, and yet another 3D vector from another library.
Now I need to code the cross product and the std::ostream &operator <<
for each one of the vectors:
constexpr sf::Vector3f cross(const sf::Vector3f &a, const sf::Vector3f &b)
{
return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
std::ostream &operator <<(std::ostream &o, const sf::Vector3f &v)
{
return o << '{' << v.x << ", " << v.y << ", " << v.z << '}';
}
// ... repeat for every 3D vector type
Which implies lots of code repetition, so I changed the approach:
template <typename vector3a_t, typename vector3b_t>
constexpr vector3a_t cross(const vector3a_t &a, const vector3b_t &b)
{
return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
Now the cross
function two types which are expected to have members x
, y
and z
but obvuiously this isn't aplicable to std::ostream &operator <<
:
template <typename vector3_t>
std::ostream &operator <<(std::ostream &o, const vector3_t &v)
{
return o << '{' << v.x << ", " << v.y << ", " << v.z << '}';
}
because the template type vector3_t
shadows everything, so I was wondering if it is possible to constrain the function to accept any type that conforms the concept of "should look like a 3D vector":
template <typename vector_t>
concept vector3_c = requires(vector_t v) { // error: expected unqualified-id
{ std::is_scalar_v<decltype(v.x)> } -> true;
{ std::is_scalar_v<decltype(v.y)> } -> true;
{ std::is_scalar_v<decltype(v.z)> } -> true;
};
template <vector3_c A, vector3_c B>
constexpr decltype(A) cross(const A &a, const B &b)
{
return { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
template <vector3_c V>
std::ostream &operator <<(std::ostream &o, const V &v)
{
return o << '{' << v.x << ", " << v.y << ", " << v.z << '}';
}
But this doesn't even compile. It's my first time attempting concepts and I don't know if what I'm trying to do is even possible.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您想要检查类型是否具有作为标量的 x,y,z 成员,您可以执行以下操作:
If what you want is to check to see if a type has x,y,z members that are scalars, you can do this:
这
只会检查表达式
std::is_scalar_v
的有效性。此外,返回类型要求限制类型而不是值,因此-> true
不正确,应该是->std::same_as
。您应该使用嵌套的
requires
来评估表达式的值,例如Demo
如果只是想检测结构体是否有有效的成员变量,使用
{vx} ->; 形式的约束表达式会更直观。 scalar
其中
auto(x)
是C++23中支持的decay-copy语言,我们可以用它来移除成员变量访问的引用。演示
This
will only check the validity of the expression
std::is_scalar_v<decltype(v.x)>
. In addition, the return-type-requirement constrains the type not the value, so-> true
is not correct, it should be->std::same_as<bool>
.You should use nested
requires
to evaluate the value of the expression, for exampleDemo
If you just want to detect whether a struct has valid member variables, it is more intuitive to use a constraint expression of the form like
{v.x} -> scalar
where
auto(x)
is the language supported decay-copy in C++23, which we can use to remove the reference of the member variable access.Demo