矢量运算符和类型转换
vector operators and type conversions
我正在创建一个数学向量 class。
我希望它的运算符提供类型之间的转换/警告行为,类似于 C++ 中 POD 类型的转换方式,例如:
//{
// auto f = 1.f;
// auto d = 2.0;
// f *= d; // warns about possible loss of data
// d *= f; // fine
// auto d2 = f * d; // fine (f promotion, d2 is double)
//}
据我了解,我需要使用 std::common_type 来找到正确的类型。不幸的是,我收到如下编译器错误:
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\type_traits(1446): error C2446: ':' : no conversion from 'Testing::Vector<float,3>' to 'float'
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> TestVector.cpp(152) : see reference to class template instantiation 'std::common_type<float,Testing::Vector<float,3>>' being compiled
相关代码如下:
template<class ElementT, unsigned int Dimensions>
class Vector
{
public:
typedef ElementT ElementT;
static const unsigned int Dimensions = Dimensions;
typedef std::array<ElementT, Dimensions> DataT;
Vector():
data() { }
explicit Vector(std::initializer_list<ElementT> values):
data()
{
std::copy(values.begin(), values.end(), data.begin());
}
template<class E>
explicit Vector(Vector<E, Dimensions> const& other):
data()
{
std::copy(other.Data().begin(), other.Data().end(), data.begin());
}
Vector& operator*=(ElementT value)
{
for (auto& e : data)
e *= value;
return *this;
}
Vector& operator*=(Vector const& other)
{
for (auto i = 0u; i != data.size(); ++i)
data[i] *= other.data[i];
return *this;
}
// etc. ...
// Warnings are still propagated from the copy constructor
// if this is used with inappropriate types...
template<class E>
operator Vector<E, Dimensions>() const
{
return Vector<E, Dimensions>(*this);
}
DataT& Data()
{
return data;
}
DataT const& Data() const
{
return data;
}
private:
friend std::ostream& operator<<(std::ostream& stream, Vector v)
{
for (auto const& e : v.data)
stream << e << " ";
return stream;
}
DataT data;
};
template<class E, unsigned int D>
Vector<E, D> operator*(Vector<E, D> const& v, E value)
{
auto result = Vector<E, D>(v);
result *= value;
return result;
}
template<class E, unsigned int D>
Vector<E, D> operator*(Vector<E, D> const& v1, Vector<E, D> const& v2)
{
auto result = Vector<E, D>(v1);
result *= v2;
return result;
}
template<class E, class T, unsigned int D>
Vector<std::common_type_t<E, T>, D> operator*(Vector<E, D> const& v, T value)
{
auto result = Vector<std::common_type_t<E, T>, D>(v);
result *= value;
return result;
}
template<class E1, class E2, unsigned int D>
Vector<std::common_type_t<E1, E2>, D> operator*(Vector<E1, D> const& v1, Vector<E2, D> const& v2)
{
auto result = Vector<std::common_type_t<E1, E2>, D>(v1);
result *= v2;
return result;
}
void TestVector()
{
std::cout << "Testing Vector" << std::endl;
using Vec3 = Vector<float, 3u>;
// Same types. All fine.
{
auto v1 = Vec3({ 1, 2, 3 });
auto v2 = Vec3({ 1, 2, 3 });
v1 *= 2.f;
v1 *= v2;
std::cout << v1 << std::endl;
}
{
auto v1 = Vec3({ 1, 2, 3 });
auto v2 = Vec3({ 1, 2, 3 });
std::cout << (v1 * 2.f) << std::endl;
std::cout << (v1 * v2) << std::endl; // causes problems with std::common_type?
}
{
auto v1 = Vector<float, 3u>({ 1, 2, 3 });
auto v2 = Vector<double, 3u>({ 1, 2, 3 });
v1 *= 2.0; // should probably produce a warning, but doesn't? :(
v1 *= v2; // compiles with warning :)
v2 *= v1; // fine :)
std::cout << v1 << std::endl;
}
{
// The std::common_type versions seem to conflict?
auto v1 = Vector<float, 3u>({ 1, 2, 3 });
auto v2 = v1 * 2.0; // v1 promotion -> should create a Vector<double, 3u>
auto v3 = v1 * v2; // v1 promotion -> should create another Vector<double, 3u>
std::cout << v2 << std::endl;
}
}
所以:
- 我需要普通版和 std::common_type 运算符版本吗?
- 使用 std::common_type 的矢量和标量版本似乎有干扰。有可能避免这种情况吗?
- 我该如何进行这项工作?
谢谢。
如果您只是在实现中使用相同的操作,实例化将生成相同的警告。
你可以试试这个例子:
#include <type_traits>
template <typename T>
struct Vect3 {
T a,b,c;
template <typename U, typename V = typename std::common_type<T, U>::type>
Vect3<V> operator*(U u) const { return {a*u,b*u,c*u}; }
template <typename U>
Vect3& operator*=(U u) { a*=u; b*=u; c*=u; return *this; }
};
int main()
{
auto f = Vect3<float>{1,2,3};
auto d = 2.0;
auto common = f * d; // fine!
f *= d; // warns about possible loss of data in the instantion of operator*=
}
GCC 即使使用 -std=c++11 -Wall -pedantic -Wextra -Wconversion -Wconversion-extra
也不会发出警告,但对于您的原始示例也不会发出警告,所以我猜 GCC
中没有相应的警告
我正在创建一个数学向量 class。
我希望它的运算符提供类型之间的转换/警告行为,类似于 C++ 中 POD 类型的转换方式,例如:
//{
// auto f = 1.f;
// auto d = 2.0;
// f *= d; // warns about possible loss of data
// d *= f; // fine
// auto d2 = f * d; // fine (f promotion, d2 is double)
//}
据我了解,我需要使用 std::common_type 来找到正确的类型。不幸的是,我收到如下编译器错误:
1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\type_traits(1446): error C2446: ':' : no conversion from 'Testing::Vector<float,3>' to 'float'
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> TestVector.cpp(152) : see reference to class template instantiation 'std::common_type<float,Testing::Vector<float,3>>' being compiled
相关代码如下:
template<class ElementT, unsigned int Dimensions>
class Vector
{
public:
typedef ElementT ElementT;
static const unsigned int Dimensions = Dimensions;
typedef std::array<ElementT, Dimensions> DataT;
Vector():
data() { }
explicit Vector(std::initializer_list<ElementT> values):
data()
{
std::copy(values.begin(), values.end(), data.begin());
}
template<class E>
explicit Vector(Vector<E, Dimensions> const& other):
data()
{
std::copy(other.Data().begin(), other.Data().end(), data.begin());
}
Vector& operator*=(ElementT value)
{
for (auto& e : data)
e *= value;
return *this;
}
Vector& operator*=(Vector const& other)
{
for (auto i = 0u; i != data.size(); ++i)
data[i] *= other.data[i];
return *this;
}
// etc. ...
// Warnings are still propagated from the copy constructor
// if this is used with inappropriate types...
template<class E>
operator Vector<E, Dimensions>() const
{
return Vector<E, Dimensions>(*this);
}
DataT& Data()
{
return data;
}
DataT const& Data() const
{
return data;
}
private:
friend std::ostream& operator<<(std::ostream& stream, Vector v)
{
for (auto const& e : v.data)
stream << e << " ";
return stream;
}
DataT data;
};
template<class E, unsigned int D>
Vector<E, D> operator*(Vector<E, D> const& v, E value)
{
auto result = Vector<E, D>(v);
result *= value;
return result;
}
template<class E, unsigned int D>
Vector<E, D> operator*(Vector<E, D> const& v1, Vector<E, D> const& v2)
{
auto result = Vector<E, D>(v1);
result *= v2;
return result;
}
template<class E, class T, unsigned int D>
Vector<std::common_type_t<E, T>, D> operator*(Vector<E, D> const& v, T value)
{
auto result = Vector<std::common_type_t<E, T>, D>(v);
result *= value;
return result;
}
template<class E1, class E2, unsigned int D>
Vector<std::common_type_t<E1, E2>, D> operator*(Vector<E1, D> const& v1, Vector<E2, D> const& v2)
{
auto result = Vector<std::common_type_t<E1, E2>, D>(v1);
result *= v2;
return result;
}
void TestVector()
{
std::cout << "Testing Vector" << std::endl;
using Vec3 = Vector<float, 3u>;
// Same types. All fine.
{
auto v1 = Vec3({ 1, 2, 3 });
auto v2 = Vec3({ 1, 2, 3 });
v1 *= 2.f;
v1 *= v2;
std::cout << v1 << std::endl;
}
{
auto v1 = Vec3({ 1, 2, 3 });
auto v2 = Vec3({ 1, 2, 3 });
std::cout << (v1 * 2.f) << std::endl;
std::cout << (v1 * v2) << std::endl; // causes problems with std::common_type?
}
{
auto v1 = Vector<float, 3u>({ 1, 2, 3 });
auto v2 = Vector<double, 3u>({ 1, 2, 3 });
v1 *= 2.0; // should probably produce a warning, but doesn't? :(
v1 *= v2; // compiles with warning :)
v2 *= v1; // fine :)
std::cout << v1 << std::endl;
}
{
// The std::common_type versions seem to conflict?
auto v1 = Vector<float, 3u>({ 1, 2, 3 });
auto v2 = v1 * 2.0; // v1 promotion -> should create a Vector<double, 3u>
auto v3 = v1 * v2; // v1 promotion -> should create another Vector<double, 3u>
std::cout << v2 << std::endl;
}
}
所以:
- 我需要普通版和 std::common_type 运算符版本吗?
- 使用 std::common_type 的矢量和标量版本似乎有干扰。有可能避免这种情况吗?
- 我该如何进行这项工作?
谢谢。
如果您只是在实现中使用相同的操作,实例化将生成相同的警告。
你可以试试这个例子:
#include <type_traits>
template <typename T>
struct Vect3 {
T a,b,c;
template <typename U, typename V = typename std::common_type<T, U>::type>
Vect3<V> operator*(U u) const { return {a*u,b*u,c*u}; }
template <typename U>
Vect3& operator*=(U u) { a*=u; b*=u; c*=u; return *this; }
};
int main()
{
auto f = Vect3<float>{1,2,3};
auto d = 2.0;
auto common = f * d; // fine!
f *= d; // warns about possible loss of data in the instantion of operator*=
}
GCC 即使使用 -std=c++11 -Wall -pedantic -Wextra -Wconversion -Wconversion-extra
也不会发出警告,但对于您的原始示例也不会发出警告,所以我猜 GCC