Browse Source

Math: make MSVC 2015 correctly pick up the float*VectorNi operator.

This complier is making my hair gray. Fortunately the out-of-class
operator doesn't conflict with the in-class one, so it's purely an
additive workaround. Adding extra checks to all subclasses to be sure
this works correctly in all cases and not just in the base class.
pull/168/head
Vladimír Vondruš 2 years ago
parent
commit
9cb623eaf9
  1. 8
      src/Magnum/Math/Color.h
  2. 21
      src/Magnum/Math/Test/ColorTest.cpp
  3. 14
      src/Magnum/Math/Test/Vector2Test.cpp
  4. 14
      src/Magnum/Math/Test/Vector3Test.cpp
  5. 14
      src/Magnum/Math/Test/Vector4Test.cpp
  6. 4
      src/Magnum/Math/Test/VectorTest.cpp
  7. 23
      src/Magnum/Math/Vector.h
  8. 4
      src/Magnum/Math/Vector2.h
  9. 4
      src/Magnum/Math/Vector3.h
  10. 4
      src/Magnum/Math/Vector4.h

8
src/Magnum/Math/Color.h

@ -715,6 +715,10 @@ template<class T> class Color3: public Vector3<T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, Color3)
};
#ifdef CORRADE_MSVC2015_COMPATIBILITY
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Color3)
#endif
/**
@brief Color in linear RGBA color space
@ -1184,6 +1188,10 @@ class Color4: public Vector4<T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, Color4)
};
#ifdef CORRADE_MSVC2015_COMPATIBILITY
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Color4)
#endif
/** @relatesalso Color3
@brief Convert color from [CIE xyY representation](https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space) to CIE XYZ

21
src/Magnum/Math/Test/ColorTest.cpp

@ -125,6 +125,8 @@ struct ColorTest: TestSuite::Tester {
void fromXyzDefaultAlpha();
void xyY();
void multiplyDivideIntegral();
void strictWeakOrdering();
void swizzleType();
@ -253,6 +255,8 @@ ColorTest::ColorTest() {
&ColorTest::fromXyzDefaultAlpha,
&ColorTest::xyY,
&ColorTest::multiplyDivideIntegral,
&ColorTest::strictWeakOrdering,
&ColorTest::swizzleType,
@ -1069,6 +1073,23 @@ void ColorTest::xyY() {
CORRADE_COMPARE(xyYToXyz(xyY), xyz);
}
void ColorTest::multiplyDivideIntegral() {
typedef Math::Color3<Int> Color3i;
typedef Math::Color4<Int> Color4i;
const Color3i vector3{32, 10, -6};
const Color4i vector4{32, 10, -6, 2};
const Color3i multiplied3{-48, -15, 9};
const Color4i multiplied4{-48, -15, 9, -3};
CORRADE_COMPARE(vector3*-1.5f, multiplied3);
CORRADE_COMPARE(vector4*-1.5f, multiplied4);
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
CORRADE_COMPARE(-1.5f*vector3, multiplied3);
CORRADE_COMPARE(-1.5f*vector4, multiplied4);
}
void ColorTest::strictWeakOrdering() {
StrictWeakOrdering o;

14
src/Magnum/Math/Test/Vector2Test.cpp

@ -71,6 +71,8 @@ struct Vector2Test: TestSuite::Tester {
void perpendicular();
void aspectRatio();
void multiplyDivideIntegral();
void strictWeakOrdering();
void swizzleType();
@ -95,6 +97,8 @@ Vector2Test::Vector2Test() {
&Vector2Test::perpendicular,
&Vector2Test::aspectRatio,
&Vector2Test::multiplyDivideIntegral,
&Vector2Test::strictWeakOrdering,
&Vector2Test::swizzleType,
@ -249,6 +253,16 @@ void Vector2Test::aspectRatio() {
CORRADE_COMPARE(Vector2(3.0f, 4.0f).aspectRatio(), 0.75f);
}
void Vector2Test::multiplyDivideIntegral() {
const Vector2i vector{32, -6};
const Vector2i multiplied{-48, 9};
CORRADE_COMPARE(vector*-1.5f, multiplied);
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
CORRADE_COMPARE(-1.5f*vector, multiplied);
}
void Vector2Test::strictWeakOrdering() {
StrictWeakOrdering o;
const Vector2 v2a{1.0f, 2.0f};

14
src/Magnum/Math/Test/Vector3Test.cpp

@ -71,6 +71,8 @@ struct Vector3Test: TestSuite::Tester {
void scales();
void twoComponent();
void multiplyDivideIntegral();
void strictWeakOrdering();
void swizzleType();
@ -96,6 +98,8 @@ Vector3Test::Vector3Test() {
&Vector3Test::scales,
&Vector3Test::twoComponent,
&Vector3Test::multiplyDivideIntegral,
&Vector3Test::strictWeakOrdering,
&Vector3Test::swizzleType,
@ -273,6 +277,16 @@ void Vector3Test::twoComponent() {
CORRADE_COMPARE(d2, 2.0f);
}
void Vector3Test::multiplyDivideIntegral() {
const Vector3i vector{32, 10, -6};
const Vector3i multiplied{-48, -15, 9};
CORRADE_COMPARE(vector*-1.5f, multiplied);
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
CORRADE_COMPARE(-1.5f*vector, multiplied);
}
void Vector3Test::strictWeakOrdering() {
StrictWeakOrdering o;
const Vector3 v3a{1.0f, 2.0f, 3.0f};

14
src/Magnum/Math/Test/Vector4Test.cpp

@ -70,6 +70,8 @@ struct Vector4Test: TestSuite::Tester {
void threeComponent();
void twoComponent();
void multiplyDivideIntegral();
void planeEquationThreePoints();
void planeEquationNormalPoint();
@ -98,6 +100,8 @@ Vector4Test::Vector4Test() {
&Vector4Test::threeComponent,
&Vector4Test::twoComponent,
&Vector4Test::multiplyDivideIntegral,
&Vector4Test::planeEquationThreePoints,
&Vector4Test::planeEquationNormalPoint,
@ -283,6 +287,16 @@ void Vector4Test::twoComponent() {
CORRADE_COMPARE(d, 1.0f);
}
void Vector4Test::multiplyDivideIntegral() {
const Vector4i vector{32, 10, -6, 2};
const Vector4i multiplied{-48, -15, 9, -3};
CORRADE_COMPARE(vector*-1.5f, multiplied);
/* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong
result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */
CORRADE_COMPARE(-1.5f*vector, multiplied);
}
void Vector4Test::planeEquationThreePoints() {
const Vector3 a{1.0f, 0.5f, 3.0f};
const Vector3 b{1.5f, 1.5f, 2.5f};

4
src/Magnum/Math/Test/VectorTest.cpp

@ -734,6 +734,10 @@ template<class T> class BasicVec2: public Math::Vector<2, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, BasicVec2)
};
#ifdef CORRADE_MSVC2015_COMPATIBILITY
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, BasicVec2)
#endif
typedef BasicVec2<Float> Vec2;
typedef BasicVec2<Int> Vec2i;

23
src/Magnum/Math/Vector.h

@ -493,6 +493,10 @@ template<std::size_t size, class T> class Vector {
*
* Same as @ref operator*(FloatingPoint) const.
*/
/* Note that this one isn't correctly picked up on MSVC 2015, there's
an out-of-class overload wrapped in CORRADE_MSVC2015_COMPATIBILITY
which is (and the two don't conflict, apparently, so both are
present) */
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint> friend Vector<size, T>
#else
@ -1442,6 +1446,25 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>&
}
#endif
#ifdef CORRADE_MSVC2015_COMPATIBILITY
/* MSVC 2015 doesn't correctly pick up the in-class inline friend that does
this, resulting in float*VectorNi expressions being wrongly executed as
int*VectorNi due to an implicit conversion fallback. This overload is picked
up correctly (and doesn't conflict with the in-class one), subclasses then
need to use the MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() overloads as well
to return a correct subtype. See VectorTest::multiplyDivideIntegral(),
VectorTest::subclass() and corresponding cases in Vector2Test, Vector3Test,
Vector4Test and ColorTest for regression tests. */
template<std::size_t size, class FloatingPoint, class Integral> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type operator*(FloatingPoint scalar, const Vector<size, Integral>& vector) {
return vector*scalar;
}
#define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(FloatingPoint scalar, const Type<Integral>& vector) { \
return vector*scalar; \
}
#endif
template<std::size_t size, class T> inline BitVector<size> Vector<size, T>::operator<(const Vector<size, T>& other) const {
BitVector<size> out;

4
src/Magnum/Math/Vector2.h

@ -235,6 +235,10 @@ template<class T> class Vector2: public Vector<2, T> {
template<class U> friend U cross(const Vector2<U>&, const Vector2<U>&);
};
#ifdef CORRADE_MSVC2015_COMPATIBILITY
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, Vector2)
#endif
namespace Implementation {
template<std::size_t, class> struct TypeForSize;
template<class T> struct TypeForSize<2, T> { typedef Math::Vector2<typename T::Type> Type; };

4
src/Magnum/Math/Vector3.h

@ -262,6 +262,10 @@ template<class T> class Vector3: public Vector<3, T> {
template<class U> friend Vector3<U> cross(const Vector3<U>&, const Vector3<U>&);
};
#ifdef CORRADE_MSVC2015_COMPATIBILITY
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Vector3)
#endif
#ifndef MAGNUM_NO_MATH_STRICT_WEAK_ORDERING
namespace Implementation {
template<class T> struct TypeForSize<3, T> { typedef Math::Vector3<typename T::Type> Type; };

4
src/Magnum/Math/Vector4.h

@ -236,6 +236,10 @@ template<class T> class Vector4: public Vector<4, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, Vector4)
};
#ifdef CORRADE_MSVC2015_COMPATIBILITY
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Vector4)
#endif
/** @relatesalso Vector4
@brief Create a plane equation from three points

Loading…
Cancel
Save