我正在创建一个数学矢量类。
我希望其运营商能够在类型之间提供转换/警告行为,类似于转换如何与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;
}
}
所以:
感谢。
答案 0 :(得分:1)
如果您只是在实现中使用相同的操作,则实例化将生成相同的警告。
你可以尝试这个例子:
#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*=
}
即使使用-std=c++11 -Wall -pedantic -Wextra -Wconversion -Wconversion-extra
,GCC也不会发出警告,但是对于您的原始示例也不会发出警告,因此我猜测GCC中没有相应的警告