diff --git a/src/Magnum/Math/Test/ColorTest.cpp b/src/Magnum/Math/Test/ColorTest.cpp index 5d00ace53..674f4f4ed 100644 --- a/src/Magnum/Math/Test/ColorTest.cpp +++ b/src/Magnum/Math/Test/ColorTest.cpp @@ -1088,6 +1088,19 @@ void ColorTest::multiplyDivideIntegral() { result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ CORRADE_COMPARE(-1.5f*vector3, multiplied3); CORRADE_COMPARE(-1.5f*vector4, multiplied4); + + constexpr Color3i cvector3{32, 10, -6}; + constexpr Color4i cvector4{32, 10, -6, 2}; + constexpr Color3i ca31 = cvector3*-1.5f; + constexpr Color4i ca41 = cvector4*-1.5f; + /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong + result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ + constexpr Color3i ca32 = -1.5f*cvector3; + constexpr Color4i ca42 = -1.5f*cvector4; + CORRADE_COMPARE(ca31, multiplied3); + CORRADE_COMPARE(ca41, multiplied4); + CORRADE_COMPARE(ca32, multiplied3); + CORRADE_COMPARE(ca42, multiplied4); } void ColorTest::strictWeakOrdering() { diff --git a/src/Magnum/Math/Test/Vector2Test.cpp b/src/Magnum/Math/Test/Vector2Test.cpp index 74bf98bd9..248825293 100644 --- a/src/Magnum/Math/Test/Vector2Test.cpp +++ b/src/Magnum/Math/Test/Vector2Test.cpp @@ -261,6 +261,14 @@ void Vector2Test::multiplyDivideIntegral() { /* 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); + + constexpr Vector2i cvector{32, -6}; + constexpr Vector2i ca1 = cvector*-1.5f; + /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong + result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ + constexpr Vector2i ca2 = -1.5f*cvector; + CORRADE_COMPARE(ca1, multiplied); + CORRADE_COMPARE(ca2, multiplied); } void Vector2Test::strictWeakOrdering() { diff --git a/src/Magnum/Math/Test/Vector3Test.cpp b/src/Magnum/Math/Test/Vector3Test.cpp index d125d686f..e55151181 100644 --- a/src/Magnum/Math/Test/Vector3Test.cpp +++ b/src/Magnum/Math/Test/Vector3Test.cpp @@ -285,6 +285,14 @@ void Vector3Test::multiplyDivideIntegral() { /* 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); + + constexpr Vector3i cvector{32, 10, -6}; + constexpr Vector3i ca1 = cvector*-1.5f; + /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong + result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ + constexpr Vector3i ca2 = -1.5f*cvector; + CORRADE_COMPARE(ca1, multiplied); + CORRADE_COMPARE(ca2, multiplied); } void Vector3Test::strictWeakOrdering() { diff --git a/src/Magnum/Math/Test/Vector4Test.cpp b/src/Magnum/Math/Test/Vector4Test.cpp index 5b9e13478..d26546676 100644 --- a/src/Magnum/Math/Test/Vector4Test.cpp +++ b/src/Magnum/Math/Test/Vector4Test.cpp @@ -299,6 +299,14 @@ void Vector4Test::multiplyDivideIntegral() { /* 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); + + constexpr Vector4i cvector{32, 10, -6, 2}; + constexpr Vector4i ca1 = cvector*-1.5f; + /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong + result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ + constexpr Vector4i ca2 = -1.5f*cvector; + CORRADE_COMPARE(ca1, multiplied); + CORRADE_COMPARE(ca2, multiplied); } void Vector4Test::planeEquationThreePoints() { diff --git a/src/Magnum/Math/Test/VectorTest.cpp b/src/Magnum/Math/Test/VectorTest.cpp index 1b8907911..23bc638c2 100644 --- a/src/Magnum/Math/Test/VectorTest.cpp +++ b/src/Magnum/Math/Test/VectorTest.cpp @@ -407,7 +407,9 @@ void VectorTest::promotedNegated() { constexpr Vector4 a{1.0f, -3.0f, 5.0f, -10.0f}; constexpr Vector4 promotedA = +a; + constexpr Vector4 negatedA = -a; CORRADE_COMPARE(promotedA, a); + CORRADE_COMPARE(negatedA, (Vector4{-1.0f, 3.0f, -5.0f, 10.0f})); } void VectorTest::addSubtract() { @@ -426,6 +428,15 @@ void VectorTest::addSubtract() { CORRADE_COMPARE(&(v -= b), &v); CORRADE_COMPARE(v, a); } + + constexpr Vector4 ca{1.0f, -3.0f, 5.0f, -10.0f}; + constexpr Vector4 cb{7.5f, 33.0f, -15.0f, 0.0f}; + constexpr Vector4 cd = ca + cb; + CORRADE_COMPARE(cd, c); + + constexpr Vector4 cc{8.5f, 30.0f, -10.0f, -10.0f}; + constexpr Vector4 ce = cc - cb; + CORRADE_COMPARE(ce, a); } void VectorTest::multiplyDivide() { @@ -447,10 +458,24 @@ void VectorTest::multiplyDivide() { CORRADE_COMPARE(v, vector); } + constexpr Vector4 cvector{1.0f, 2.0f, 3.0f, 4.0f}; + constexpr Vector4 ca1 = cvector*-1.5f; + constexpr Vector4 ca2 = -1.5f*cvector; + CORRADE_COMPARE(ca1, multiplied); + CORRADE_COMPARE(ca2, multiplied); + + constexpr Vector4 cmultiplied{-1.5f, -3.0f, -4.5f, -6.0f}; + constexpr Vector4 cb = cmultiplied/-1.5f; + CORRADE_COMPARE(cb, vector); + /* Divide a vector with a scalar and invert */ const Vector4 divisor{1.0f, 2.0f, -4.0f, 8.0f}; const Vector4 result{1.0f, 0.5f, -0.25f, 0.125f}; CORRADE_COMPARE(1.0f/divisor, result); + + constexpr Vector4 cdivisor(1.0f, 2.0f, -4.0f, 8.0f); + constexpr Vector4 ce = 1.0f/cdivisor; + CORRADE_COMPARE(ce, result); } void VectorTest::multiplyDivideIntegral() { @@ -472,6 +497,16 @@ void VectorTest::multiplyDivideIntegral() { CORRADE_COMPARE(v, vector); } + constexpr Vector4i cvector{32, 10, -6, 2}; + constexpr Vector4i ca1 = cvector*-1.5f; + constexpr Vector4i ca2 = -1.5f*cvector; + CORRADE_COMPARE(ca1, multiplied); + CORRADE_COMPARE(ca2, multiplied); + + constexpr Vector4i cmultiplied{-48, -15, 9, -3}; + constexpr Vector4i cb = cmultiplied/-1.5f; + CORRADE_COMPARE(cb, cvector); + /* Using integer vector as divisor is not supported */ } @@ -493,6 +528,14 @@ void VectorTest::multiplyDivideComponentWise() { CORRADE_COMPARE(&(v /= multiplier), &v); CORRADE_COMPARE(v, vec); } + + constexpr Vector4 cvec{1.0f, 2.0f, 3.0f, 4.0f}; + constexpr Vector4 cmultiplier{7.0f, -4.0f, -1.5f, 1.0f}; + constexpr Vector4 cmultiplied{7.0f, -8.0f, -4.5f, 4.0f}; + constexpr Vector4 ca = cvec*cmultiplier; + constexpr Vector4 cb = cmultiplied/cmultiplier; + CORRADE_COMPARE(ca, multiplied); + CORRADE_COMPARE(cb, vec); } void VectorTest::multiplyDivideComponentWiseIntegral() { @@ -515,6 +558,17 @@ void VectorTest::multiplyDivideComponentWiseIntegral() { CORRADE_COMPARE(v, vec); } + constexpr Vector4i cvec{7, 2, -16, -1}; + constexpr Vector4 cmultiplier{2.0f, -1.5f, 0.5f, 10.0f}; + constexpr Vector4i ca1 = cvec*cmultiplier; + constexpr Vector4i ca2 = cmultiplier*cvec; + CORRADE_COMPARE(ca1, multiplied); + CORRADE_COMPARE(ca2, multiplied); + + constexpr Vector4i cmultiplied{14, -3, -8, -10}; + constexpr Vector4i cb = cmultiplied/cmultiplier; + CORRADE_COMPARE(cb, cvec); + /* Using integer vector as divisor is not supported */ } @@ -535,6 +589,13 @@ void VectorTest::modulo() { CORRADE_COMPARE(&(v %= b), &v); CORRADE_COMPARE(v, (Vector4i{0, 3, 63, -2})); } + + constexpr Vector4i ca{4, 13, 255, -6}; + constexpr Vector4i cb{2, 5, 64, -4}; + constexpr Vector4i cc = ca % 2; + constexpr Vector4i cd = ca % cb; + CORRADE_COMPARE(cc, (Vector4i{0, 1, 1, 0})); + CORRADE_COMPARE(cd, (Vector4i{0, 3, 63, -2})); } void VectorTest::bitwise() { @@ -563,6 +624,17 @@ void VectorTest::bitwise() { CORRADE_COMPARE(v, (Vector4i{255, 165, -254, -44})); } + constexpr Vector4i ca{85, 240, -241, 33}; + constexpr Vector4i cb{170, 85, 13, -11}; + constexpr Vector4i cd = ~ca; + constexpr Vector4i ce = ca & cb; + constexpr Vector4i cf = ca | cb; + constexpr Vector4i cg = ca ^ cb; + CORRADE_COMPARE(cd, (Vector4i{-86, -241, 240, -34})); + CORRADE_COMPARE(ce, (Vector4i{0, 80, 13, 33})); + CORRADE_COMPARE(cf, (Vector4i{255, 245, -241, -11})); + CORRADE_COMPARE(cg, (Vector4i{255, 165, -254, -44})); + const Vector4i c{7, 32, 1, 15}; CORRADE_COMPARE(c << 2, (Vector4i{28, 128, 4, 60})); { @@ -577,6 +649,12 @@ void VectorTest::bitwise() { CORRADE_COMPARE(&(v >>= 2), &v); CORRADE_COMPARE(v, (Vector4i{1, 8, 0, 3})); } + + constexpr Vector4i cc{7, 32, 1, 15}; + constexpr Vector4i ch = cc << 2; + constexpr Vector4i ci = cc >> 2; + CORRADE_COMPARE(ch, (Vector4i{28, 128, 4, 60})); + CORRADE_COMPARE(ci, (Vector4i{1, 8, 0, 3})); } void VectorTest::dot() { @@ -855,6 +933,11 @@ void VectorTest::subclass() { } CORRADE_COMPARE(-Vec2(-2.0f, 5.0f), Vec2(2.0f, -5.0f)); + { + constexpr Vec2 ca{-2.0f, 5.0f}; + constexpr Vec2 cb = -ca; + CORRADE_COMPARE(cb, (Vec2{2.0f, -5.0f})); + } /* Addition / subtraction */ CORRADE_COMPARE(Vec2(-2.0f, 5.0f) + Vec2(1.0f, -3.0f), Vec2(-1.0f, 2.0f)); @@ -862,6 +945,11 @@ void VectorTest::subclass() { Vec2 a{-2.0f, 5.0f}; CORRADE_COMPARE(&(a += Vec2{1.0f, -3.0f}), &a); CORRADE_COMPARE(a, (Vec2{-1.0f, 2.0f})); + + constexpr Vec2 ca{-2.0f, 5.0f}; + constexpr Vec2 cb{1.0f, -3.0f}; + constexpr Vec2 cc = ca + cb; + CORRADE_COMPARE(cc, (Vec2{-1.0f, 2.0f})); } CORRADE_COMPARE(Vec2(-2.0f, 5.0f) - Vec2(1.0f, -3.0f), Vec2(-3.0f, 8.0f)); @@ -869,6 +957,11 @@ void VectorTest::subclass() { Vec2 a{-2.0f, 5.0f}; CORRADE_COMPARE(&(a -= Vec2{1.0f, -3.0f}), &a); CORRADE_COMPARE(a, (Vec2{-3.0f, 8.0f})); + + constexpr Vec2 ca{-2.0f, 5.0f}; + constexpr Vec2 cb{1.0f, -3.0f}; + constexpr Vec2 cc = ca - cb; + CORRADE_COMPARE(cc, (Vec2{-3.0f, 8.0f})); } /* Multiplication and division with a scalar */ @@ -878,6 +971,12 @@ void VectorTest::subclass() { Vec2 a{-2.0f, 5.0f}; CORRADE_COMPARE(&(a *= 2.0f), &a); CORRADE_COMPARE(a, (Vec2{-4.0f, 10.0f})); + + constexpr Vec2 ca{-2.0f, 5.0f}; + constexpr Vec2 cb1 = ca*2.0f; + constexpr Vec2 cb2 = 2.0f*ca; + CORRADE_COMPARE(cb1, (Vec2{-4.0f, 10.0f})); + CORRADE_COMPARE(cb2, (Vec2{-4.0f, 10.0f})); } CORRADE_COMPARE(Vec2(-2.0f, 5.0f)/0.5f, Vec2(-4.0f, 10.0f)); @@ -886,6 +985,12 @@ void VectorTest::subclass() { Vec2 a{-2.0f, 5.0f}; CORRADE_COMPARE(&(a /= 0.5f), &a); CORRADE_COMPARE(a, (Vec2{-4.0f, 10.0f})); + + constexpr Vec2 ca{-2.0f, 5.0f}; + constexpr Vec2 cb1 = ca/0.5f; + constexpr Vec2 cb2 = 2.0f/ca; + CORRADE_COMPARE(cb1, (Vec2{-4.0f, 10.0f})); + CORRADE_COMPARE(cb2, (Vec2{-1.0f, 0.4f})); } /* Multiplication/division with an integer scalar */ @@ -895,6 +1000,12 @@ void VectorTest::subclass() { Vec2i a{2, 4}; CORRADE_COMPARE(&(a *= 1.5f), &a); CORRADE_COMPARE(a, (Vec2i{3, 6})); + + constexpr Vec2i ca{2, 4}; + constexpr Vec2i cb1 = ca*1.5f; + constexpr Vec2i cb2 = 1.5f*ca; + CORRADE_COMPARE(cb1, (Vec2i{3, 6})); + CORRADE_COMPARE(cb2, (Vec2i{3, 6})); } { @@ -907,6 +1018,10 @@ void VectorTest::subclass() { Vec2i a{2, 4}; CORRADE_COMPARE(&(a /= (2.0f/3.0f)), &a); CORRADE_COMPARE(a, (Vec2i{3, 6})); + + constexpr Vec2i ca{2, 4}; + constexpr Vec2i cb = ca/(2.0f/3.0f); + CORRADE_COMPARE(cb, (Vec2i{3, 6})); } /* Multiplication and division with a vector */ @@ -915,6 +1030,11 @@ void VectorTest::subclass() { Vec2 a{-2.0f, 5.0f}; CORRADE_COMPARE(&(a *= Vec2{1.5f, -2.0f}), &a); CORRADE_COMPARE(a, (Vec2{-3.0f, -10.0f})); + + constexpr Vec2 ca{-2.0f, 5.0f}; + constexpr Vec2 cb{1.5f, -2.0f}; + constexpr Vec2 cc = ca*cb; + CORRADE_COMPARE(cc, (Vec2{-3.0f, -10.0f})); } CORRADE_COMPARE(Vec2(-2.0f, 5.0f)/Vec2(2.0f/3.0f, -0.5f), Vec2(-3.0f, -10.0f)); @@ -922,6 +1042,11 @@ void VectorTest::subclass() { Vec2 a{-2.0f, 5.0f}; CORRADE_COMPARE(&(a /= Vec2{2.0f/3.0f, -0.5f}), &a); CORRADE_COMPARE(a, (Vec2{-3.0f, -10.0f})); + + constexpr Vec2 ca{-2.0f, 5.0f}; + constexpr Vec2 cb{2.0f/3.0f, -0.5f}; + constexpr Vec2 cc = ca/cb; + CORRADE_COMPARE(cc, (Vec2{-3.0f, -10.0f})); } /* Multiplication/division with an integer vector */ @@ -931,6 +1056,13 @@ void VectorTest::subclass() { Vec2i a{2, 4}; CORRADE_COMPARE(&(a *= Vec2{-1.5f, 0.5f}), &a); CORRADE_COMPARE(a, (Vec2i{-3, 2})); + + constexpr Vec2i ca{2, 4}; + constexpr Vec2 cb{-1.5f, 0.5f}; + constexpr Vec2i cc1 = ca*cb; + constexpr Vec2i cc2 = cb*ca; + CORRADE_COMPARE(cc1, (Vec2i{-3, 2})); + CORRADE_COMPARE(cc2, (Vec2i{-3, 2})); } { @@ -943,6 +1075,11 @@ void VectorTest::subclass() { Vec2i a{2, 4}; CORRADE_COMPARE(&(a /= Vec2{-2.0f/3.0f, 2.0f}), &a); CORRADE_COMPARE(a, (Vec2i{-3, 2})); + + constexpr Vec2i ca{2, 4}; + constexpr Vec2 cb{-2.0f/3.0f, 2.0f}; + constexpr Vec2i cc = ca/cb; + CORRADE_COMPARE(cc, (Vec2i{-3, 2})); } /* Modulo operations */ @@ -951,6 +1088,10 @@ void VectorTest::subclass() { Vec2i a{4, 13}; CORRADE_COMPARE(&(a %= 2), &a); CORRADE_COMPARE(a, (Vec2i{0, 1})); + + constexpr Vec2i ca{4, 13}; + constexpr Vec2i cb = ca % 2; + CORRADE_COMPARE(cb, (Vec2i{0, 1})); } CORRADE_COMPARE(Vec2i(4, 13) % Vec2i(2, 5), Vec2i(0, 3)); @@ -958,10 +1099,20 @@ void VectorTest::subclass() { Vec2i a{4, 13}; CORRADE_COMPARE(&(a %= Vec2i{2, 5}), &a); CORRADE_COMPARE(a, (Vec2i{0, 3})); + + constexpr Vec2i ca{4, 13}; + constexpr Vec2i cb{2, 5}; + constexpr Vec2i cc = ca % cb; + CORRADE_COMPARE(cc, (Vec2i{0, 3})); } /* Unary bitwise operations */ CORRADE_COMPARE(~Vec2i(85, 240), Vec2i(-86, -241)); + { + constexpr Vec2i ca{85, 240}; + constexpr Vec2i cb = ~ca; + CORRADE_COMPARE(cb, (Vec2i{-86, -241})); + } /* Bitwise AND, OR and XOR */ CORRADE_COMPARE(Vec2i(85, 240) & Vec2i(170, 85), Vec2i(0, 80)); @@ -969,6 +1120,11 @@ void VectorTest::subclass() { Vec2i a{85, 240}; CORRADE_COMPARE(&(a &= Vec2i{170, 85}), &a); CORRADE_COMPARE(a, (Vec2i{0, 80})); + + constexpr Vec2i ca{85, 240}; + constexpr Vec2i cb{170, 85}; + constexpr Vec2i cc = ca & cb; + CORRADE_COMPARE(cc, (Vec2i{0, 80})); } CORRADE_COMPARE(Vec2i(85, 240) | Vec2i(170, 85), Vec2i(255, 245)); @@ -976,6 +1132,11 @@ void VectorTest::subclass() { Vec2i a{85, 240}; CORRADE_COMPARE(&(a |= Vec2i{170, 85}), &a); CORRADE_COMPARE(a, (Vec2i{255, 245})); + + constexpr Vec2i ca{85, 240}; + constexpr Vec2i cb{170, 85}; + constexpr Vec2i cc = ca | cb; + CORRADE_COMPARE(cc, (Vec2i{255, 245})); } CORRADE_COMPARE(Vec2i(85, 240) ^ Vec2i(170, 85), Vec2i(255, 165)); @@ -983,6 +1144,11 @@ void VectorTest::subclass() { Vec2i a{85, 240}; CORRADE_COMPARE(&(a ^= Vec2i{170, 85}), &a); CORRADE_COMPARE(a, (Vec2i{255, 165})); + + constexpr Vec2i ca{85, 240}; + constexpr Vec2i cb{170, 85}; + constexpr Vec2i cc = ca ^ cb; + CORRADE_COMPARE(cc, (Vec2i{255, 165})); } /* Bit shift */ @@ -991,6 +1157,10 @@ void VectorTest::subclass() { Vec2i a{7, 32}; CORRADE_COMPARE(&(a <<= 2), &a); CORRADE_COMPARE(a, (Vec2i{28, 128})); + + constexpr Vec2i ca{7, 32}; + constexpr Vec2i cb = ca << 2; + CORRADE_COMPARE(cb, (Vec2i{28, 128})); } CORRADE_COMPARE(Vec2i(7, 32) >> 2, Vec2i(1, 8)); @@ -998,6 +1168,10 @@ void VectorTest::subclass() { Vec2i a{7, 32}; CORRADE_COMPARE(&(a >>= 2), &a); CORRADE_COMPARE(a, (Vec2i{1, 8})); + + constexpr Vec2i ca{7, 32}; + constexpr Vec2i cb = ca >> 2; + CORRADE_COMPARE(cb, (Vec2i{1, 8})); } /* Functions */ diff --git a/src/Magnum/Math/Vector.h b/src/Magnum/Math/Vector.h index 7feee1aef..8e00bd8cc 100644 --- a/src/Magnum/Math/Vector.h +++ b/src/Magnum/Math/Vector.h @@ -356,11 +356,13 @@ template class Vector { * @see @ref flipped(), @ref Vector2::perpendicular() */ #ifdef DOXYGEN_GENERATING_OUTPUT - Vector + constexpr Vector #else - template typename std::enable_if::value, Vector>::type + template constexpr typename std::enable_if::value, Vector>::type #endif - operator-() const; + operator-() const { + return negateInternal(typename Containers::Implementation::GenerateSequence::Type{}); + } /** * @brief Add and assign a vector @@ -381,9 +383,8 @@ template class Vector { * * @see @ref operator+=(), @ref sum() */ - Vector operator+(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) += other; + constexpr Vector operator+(const Vector& other) const { + return addInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -405,9 +406,8 @@ template class Vector { * * @see @ref operator-=() */ - Vector operator-(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) -= other; + constexpr Vector operator-(const Vector& other) const { + return subtractInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -433,9 +433,8 @@ template class Vector { * @ref operator*=(T), @ref operator*(T, const Vector&), * @ref operator*(FloatingPoint) const */ - Vector operator*(T scalar) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) *= scalar; + constexpr Vector operator*(T scalar) const { + return multiplyInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -443,7 +442,7 @@ template class Vector { * * Same as @ref operator*(T) const. */ - friend Vector operator*( + constexpr friend Vector operator*( #ifdef DOXYGEN_GENERATING_OUTPUT T #else @@ -479,13 +478,12 @@ template class Vector { * is done in floating-point. */ #ifdef DOXYGEN_GENERATING_OUTPUT - template Vector + template constexpr Vector #else - template typename std::enable_if::value && std::is_floating_point::value, Vector>::type + template constexpr typename std::enable_if::value && std::is_floating_point::value, Vector>::type #endif operator*(FloatingPoint scalar) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) *= scalar; + return multiplyIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -498,9 +496,9 @@ template class Vector { which is (and the two don't conflict, apparently, so both are present) */ #ifdef DOXYGEN_GENERATING_OUTPUT - template friend Vector + template friend constexpr Vector #else - template friend typename std::enable_if::value && std::is_floating_point::value, Vector>::type + template friend constexpr typename std::enable_if::value && std::is_floating_point::value, Vector>::type #endif operator*(FloatingPoint scalar, const Vector& vector) { return vector*scalar; @@ -529,9 +527,8 @@ template class Vector { * @ref operator/=(T), @ref operator/(T, const Vector&), * @ref operator/(FloatingPoint) const */ - Vector operator/(T scalar) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) /= scalar; + constexpr Vector operator/(T scalar) const { + return divideInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -542,7 +539,7 @@ template class Vector { * @f] * @see @ref operator/(T) const */ - friend Vector operator/( + friend constexpr Vector operator/( #ifdef DOXYGEN_GENERATING_OUTPUT T #else @@ -550,12 +547,7 @@ template class Vector { #endif scalar, const Vector& vector) { - Vector out; - - for(std::size_t i = 0; i != size; ++i) - out._data[i] = scalar/vector._data[i]; - - return out; + return divideInternal(scalar, vector, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -583,13 +575,12 @@ template class Vector { * in floating-point. */ #ifdef DOXYGEN_GENERATING_OUTPUT - template Vector + template Vector constexpr #else - template typename std::enable_if::value && std::is_floating_point::value, Vector>::type + template constexpr typename std::enable_if::value && std::is_floating_point::value, Vector>::type #endif operator/(FloatingPoint scalar) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) /= scalar; + return divideIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -615,9 +606,8 @@ template class Vector { * @ref operator*(const Vector&) const, * @ref product() */ - Vector operator*(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) *= other; + constexpr Vector operator*(const Vector& other) const { + return multiplyInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -651,9 +641,8 @@ template class Vector { #ifndef DOXYGEN_GENERATING_OUTPUT , class Integral = T, typename std::enable_if::value && std::is_floating_point::value>::type* = nullptr #endif - > Vector operator*(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) *= other; + > constexpr Vector operator*(const Vector& other) const { + return multiplyIntegerInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -670,7 +659,7 @@ template class Vector { #ifndef DOXYGEN_GENERATING_OUTPUT , class FloatingPoint = T, typename std::enable_if::value && std::is_floating_point::value>::type* = nullptr #endif - > Vector operator*(const Vector& other) const { + > constexpr Vector operator*(const Vector& other) const { return other**this; } @@ -696,9 +685,8 @@ template class Vector { * @see @ref operator/(T) const, @ref operator/=(const Vector&), * @ref operator/(const Vector&) const */ - Vector operator/(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) /= other; + constexpr Vector operator/(const Vector& other) const { + return divideInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -729,13 +717,12 @@ template class Vector { * floating-point type to have a floating-point result. */ #ifdef DOXYGEN_GENERATING_OUTPUT - template Vector + template constexpr Vector #else - template typename std::enable_if::value && std::is_floating_point::value, Vector>::type + template constexpr typename std::enable_if::value && std::is_floating_point::value, Vector>::type #endif operator/(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) /= other; + return divideIntegerInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -761,13 +748,12 @@ template class Vector { * Enabled only for integral types. */ #ifdef DOXYGEN_GENERATING_OUTPUT - Vector + constexpr Vector #else - template typename std::enable_if::value, Vector>::type + template constexpr typename std::enable_if::value, Vector>::type #endif operator%(T scalar) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) %= scalar; + return moduloInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -793,13 +779,12 @@ template class Vector { * Enabled only for integral types. */ #ifdef DOXYGEN_GENERATING_OUTPUT - Vector + constexpr Vector #else - template typename std::enable_if::value, Vector>::type + template constexpr typename std::enable_if::value, Vector>::type #endif operator%(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) %= other; + return moduloInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -808,17 +793,12 @@ template class Vector { * Enabled only for integral types. */ #ifdef DOXYGEN_GENERATING_OUTPUT - Vector + constexpr Vector #else - template typename std::enable_if::value, Vector>::type + template constexpr typename std::enable_if::value, Vector>::type #endif operator~() const { - Vector out; - - for(std::size_t i = 0; i != size; ++i) - out._data[i] = ~_data[i]; - - return out; + return invertInternal(typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -844,13 +824,12 @@ template class Vector { * Enabled only for integral types. */ #ifdef DOXYGEN_GENERATING_OUTPUT - Vector + constexpr Vector #else - template typename std::enable_if::value, Vector>::type + template constexpr typename std::enable_if::value, Vector>::type #endif operator&(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) &= other; + return andInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -876,13 +855,12 @@ template class Vector { * Enabled only for integral types. */ #ifdef DOXYGEN_GENERATING_OUTPUT - Vector + constexpr Vector #else - template typename std::enable_if::value, Vector>::type + template constexpr typename std::enable_if::value, Vector>::type #endif operator|(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) |= other; + return orInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -908,13 +886,12 @@ template class Vector { * Enabled only for integral types. */ #ifdef DOXYGEN_GENERATING_OUTPUT - Vector + constexpr Vector #else - template typename std::enable_if::value, Vector>::type + template constexpr typename std::enable_if::value, Vector>::type #endif operator^(const Vector& other) const { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) ^= other; + return xorInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -940,14 +917,13 @@ template class Vector { * Enabled only for integral types. */ #ifdef DOXYGEN_GENERATING_OUTPUT - Vector operator<<(T shift) const + constexpr Vector operator<<(T shift) const #else - template typename std::enable_if::value, Vector>::type + template constexpr typename std::enable_if::value, Vector>::type operator<<(typename std::common_type::type shift) const #endif { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) <<= shift; + return shiftLeftInternal(shift, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -973,14 +949,13 @@ template class Vector { * Enabled only for integral types. */ #ifdef DOXYGEN_GENERATING_OUTPUT - Vector operator>>(T shift) const + constexpr Vector operator>>(T shift) const #else template - typename std::enable_if::value, Vector>::type operator>>(typename std::common_type::type shift) const + constexpr typename std::enable_if::value, Vector>::type operator>>(typename std::common_type::type shift) const #endif { - /* MSVC 2015 and 2017 treat the copy as a const if {} is used */ - return Vector(*this) >>= shift; + return shiftRightInternal(shift, typename Containers::Implementation::GenerateSequence::Type{}); } /** @@ -1168,6 +1143,86 @@ template class Vector { builds */ T _data[size]; + /* Implementation for constexpr operators. Not SFINAE-restricted for + integers or integers + floats, not marked as inline friends, no + std::common_type workarounds for scalars as the callers do all + that already. Protected as they're used directly by subclasses + through the MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION() macro to speed + up debug builds. */ + template constexpr Vector negateInternal(Containers::Implementation::Sequence) const { + /* All these explicitly cast to T because with e.g. Vector2s it + would otherwise cause narrowing warnings because stupid C + promotion rules make e.g. `short + short` result in an int */ + return {T(-_data[sequence])...}; + } + template constexpr Vector addInternal(const Vector& other, Containers::Implementation::Sequence) const { + return {T(_data[sequence] + other._data[sequence])...}; + } + template constexpr Vector subtractInternal(const Vector& other, Containers::Implementation::Sequence) const { + return {T(_data[sequence] - other._data[sequence])...}; + } + template constexpr Vector multiplyInternal(T scalar, Containers::Implementation::Sequence) const { + return {T(_data[sequence]*scalar)...}; + } + template constexpr Vector multiplyIntegerInternal(FloatingPoint scalar, Containers::Implementation::Sequence) const { + /* This has to cast even without C promotion rules in effect, to + convert a floating-point result back to an integer */ + return {T(_data[sequence]*scalar)...}; + } + template constexpr Vector divideInternal(T scalar, Containers::Implementation::Sequence) const { + return {T(_data[sequence]/scalar)...}; + } + template constexpr Vector divideIntegerInternal(FloatingPoint scalar, Containers::Implementation::Sequence) const { + /* This has to cast even without C promotion rules in effect, to + convert a floating-point result back to an integer */ + return {T(_data[sequence]/scalar)...}; + } + template constexpr static Vector divideInternal(T scalar, const Vector& vector, Containers::Implementation::Sequence) { + return {T(scalar/vector._data[sequence])...}; + } + template constexpr Vector multiplyInternal(const Vector& other, Containers::Implementation::Sequence) const { + return {T(_data[sequence]*other._data[sequence])...}; + } + template constexpr Vector multiplyIntegerInternal(const Vector& other, Containers::Implementation::Sequence) const { + /* This has to cast even without C promotion rules in effect, to + convert a floating-point result back to an integer */ + return {T(_data[sequence]*other._data[sequence])...}; + } + template constexpr Vector divideInternal(const Vector& other, Containers::Implementation::Sequence) const { + return {T(_data[sequence]/other._data[sequence])...}; + } + template constexpr Vector divideIntegerInternal(const Vector& other, Containers::Implementation::Sequence) const { + /* This has to cast even without C promotion rules in effect, to + convert a floating-point result back to an integer */ + return {T(_data[sequence]/other._data[sequence])...}; + } + + template constexpr Vector moduloInternal(T scalar, Containers::Implementation::Sequence) const { + return {T(_data[sequence] % scalar)...}; + } + template constexpr Vector moduloInternal(const Math::Vector& other, Containers::Implementation::Sequence) const { + return {T(_data[sequence] % other._data[sequence])...}; + } + + template constexpr Vector invertInternal(Containers::Implementation::Sequence) const { + return {T(~_data[sequence])...}; + } + template constexpr Vector andInternal(const Math::Vector& other, Containers::Implementation::Sequence) const { + return {T(_data[sequence] & other._data[sequence])...}; + } + template constexpr Vector orInternal(const Math::Vector& other, Containers::Implementation::Sequence) const { + return {T(_data[sequence] | other._data[sequence])...}; + } + template constexpr Vector xorInternal(const Math::Vector& other, Containers::Implementation::Sequence) const { + return {T(_data[sequence] ^ other._data[sequence])...}; + } + template constexpr Vector shiftLeftInternal(typename std::common_type::type shift, Containers::Implementation::Sequence) const { + return {T(_data[sequence] << shift)...}; + } + template constexpr Vector shiftRightInternal(typename std::common_type::type shift, Containers::Implementation::Sequence) const { + return {T(_data[sequence] >> shift)...}; + } + private: #ifndef DOXYGEN_GENERATING_OUTPUT /* Since I added deprecated aliases to Shaders::VectorGL, this FUCKING @@ -1270,178 +1325,178 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>& #endif #ifndef DOXYGEN_GENERATING_OUTPUT -#define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(size, Type) \ - static Type& from(T* data) { \ - return *reinterpret_cast*>(data); \ +#define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(size, Type_) \ + static Type_& from(T* data) { \ + return *reinterpret_cast*>(data); \ } \ - static const Type& from(const T* data) { \ - return *reinterpret_cast*>(data); \ + static const Type_& from(const T* data) { \ + return *reinterpret_cast*>(data); \ } \ - template constexpr static Type pad(const Math::Vector& a, T value = T()) { \ + template constexpr static Type_ pad(const Math::Vector& a, T value = T()) { \ return Math::Vector::pad(a, value); \ } \ \ - constexpr Type operator+() const { \ + constexpr Type_ operator+() const { \ return Math::Vector::operator+(); \ } \ - template typename std::enable_if::value, Type>::type \ + template constexpr typename std::enable_if::value, Type_>::type \ operator-() const { \ - return Math::Vector::operator-(); \ + return Math::Vector::negateInternal(typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - Type& operator+=(const Math::Vector& other) { \ + Type_& operator+=(const Math::Vector& other) { \ Math::Vector::operator+=(other); \ return *this; \ } \ - Type operator+(const Math::Vector& other) const { \ - return Math::Vector::operator+(other); \ + constexpr Type_ operator+(const Math::Vector& other) const { \ + return Math::Vector::addInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - Type& operator-=(const Math::Vector& other) { \ + Type_& operator-=(const Math::Vector& other) { \ Math::Vector::operator-=(other); \ return *this; \ } \ - Type operator-(const Math::Vector& other) const { \ - return Math::Vector::operator-(other); \ + constexpr Type_ operator-(const Math::Vector& other) const { \ + return Math::Vector::subtractInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ \ - Type& operator*=(T scalar) { \ + Type_& operator*=(T scalar) { \ Math::Vector::operator*=(scalar); \ return *this; \ } \ - Type operator*(T scalar) const { \ - return Math::Vector::operator*(scalar); \ + constexpr Type_ operator*(T scalar) const { \ + return Math::Vector::multiplyInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - friend Type operator*(typename std::common_type::type scalar, const Type& vector) { \ + friend constexpr Type_ operator*(typename std::common_type::type scalar, const Type_& vector) { \ return scalar*static_cast&>(vector); \ } \ - template typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(FloatingPoint scalar) { \ + template typename std::enable_if::value && std::is_floating_point::value, Type_&>::type operator*=(FloatingPoint scalar) { \ Math::Vector::operator*=(scalar); \ return *this; \ } \ - template typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint scalar) const { \ - return Math::Vector::operator*(scalar); \ + template constexpr typename std::enable_if::value && std::is_floating_point::value, Type_>::type operator*(FloatingPoint scalar) const { \ + return Math::Vector::multiplyIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template friend typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint scalar, const Type& vector) { \ + template friend constexpr typename std::enable_if::value && std::is_floating_point::value, Type_>::type operator*(FloatingPoint scalar, const Type_& vector) { \ return scalar*static_cast&>(vector); \ } \ \ - Type& operator/=(T scalar) { \ + Type_& operator/=(T scalar) { \ Math::Vector::operator/=(scalar); \ return *this; \ } \ - Type operator/(T scalar) const { \ - return Math::Vector::operator/(scalar); \ + constexpr Type_ operator/(T scalar) const { \ + return Math::Vector::divideInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - friend Type operator/(typename std::common_type::type scalar, const Type& vector) { \ + friend constexpr Type_ operator/(typename std::common_type::type scalar, const Type_& vector) { \ return scalar/static_cast&>(vector); \ } \ - template typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(FloatingPoint scalar) { \ + template typename std::enable_if::value && std::is_floating_point::value, Type_&>::type operator/=(FloatingPoint scalar) { \ Math::Vector::operator/=(scalar); \ return *this; \ } \ - template typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(FloatingPoint scalar) const { \ - return Math::Vector::operator/(scalar); \ + template constexpr typename std::enable_if::value && std::is_floating_point::value, Type_>::type operator/(FloatingPoint scalar) const { \ + return Math::Vector::divideIntegerInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ \ - Type& operator*=(const Math::Vector& other) { \ + Type_& operator*=(const Math::Vector& other) { \ Math::Vector::operator*=(other); \ return *this; \ } \ - Type operator*(const Math::Vector& other) const { \ - return Math::Vector::operator*(other); \ + constexpr Type_ operator*(const Math::Vector& other) const { \ + return Math::Vector::multiplyInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(const Math::Vector& other) { \ + template typename std::enable_if::value && std::is_floating_point::value, Type_&>::type operator*=(const Math::Vector& other) { \ Math::Vector::operator*=(other); \ return *this; \ } \ - template::value && std::is_floating_point::value>::type* = nullptr> Type operator*(const Math::Vector& other) const { \ - return Math::Vector::operator*(other); \ + template::value && std::is_floating_point::value>::type* = nullptr> constexpr Type_ operator*(const Math::Vector& other) const { \ + return Math::Vector::multiplyIntegerInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template::value && std::is_floating_point::value>::type* = nullptr> Type operator*(const Math::Vector& other) const { \ - return Math::Vector::operator*(other); \ + template::value && std::is_floating_point::value>::type* = nullptr> constexpr Type_ operator*(const Math::Vector& other) const { \ + return other**this; \ } \ \ - Type& operator/=(const Math::Vector& other) { \ + Type_& operator/=(const Math::Vector& other) { \ Math::Vector::operator/=(other); \ return *this; \ } \ - Type operator/(const Math::Vector& other) const { \ - return Math::Vector::operator/(other); \ + constexpr Type_ operator/(const Math::Vector& other) const { \ + return Math::Vector::divideInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(const Math::Vector& other) { \ + template typename std::enable_if::value && std::is_floating_point::value, Type_&>::type operator/=(const Math::Vector& other) { \ Math::Vector::operator/=(other); \ return *this; \ } \ - template typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(const Math::Vector& other) const { \ - return Math::Vector::operator/(other); \ + template constexpr typename std::enable_if::value && std::is_floating_point::value, Type_>::type operator/(const Math::Vector& other) const { \ + return Math::Vector::divideIntegerInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ \ - template typename std::enable_if::value, Type&>::type operator%=(T scalar) { \ + template typename std::enable_if::value, Type_&>::type operator%=(T scalar) { \ Math::Vector::operator%=(scalar); \ return *this; \ } \ - template typename std::enable_if::value, Type>::type operator%(T scalar) const { \ - return Math::Vector::operator%(scalar); \ + template constexpr typename std::enable_if::value, Type_>::type operator%(T scalar) const { \ + return Math::Vector::moduloInternal(scalar, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template typename std::enable_if::value, Type&>::type operator%=(const Math::Vector& other) { \ + template typename std::enable_if::value, Type_&>::type operator%=(const Math::Vector& other) { \ Math::Vector::operator%=(other); \ return *this; \ } \ - template typename std::enable_if::value, Type>::type operator%(const Math::Vector& other) const { \ - return Math::Vector::operator%(other); \ + template constexpr typename std::enable_if::value, Type_>::type operator%(const Math::Vector& other) const { \ + return Math::Vector::moduloInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ \ - template typename std::enable_if::value, Type>::type operator~() const { \ - return Math::Vector::operator~(); \ + template constexpr typename std::enable_if::value, Type_>::type operator~() const { \ + return Math::Vector::invertInternal(typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template typename std::enable_if::value, Type&>::type operator&=(const Math::Vector& other) { \ + template typename std::enable_if::value, Type_&>::type operator&=(const Math::Vector& other) { \ Math::Vector::operator&=(other); \ return *this; \ } \ - template typename std::enable_if::value, Type>::type operator&(const Math::Vector& other) const { \ - return Math::Vector::operator&(other); \ + template constexpr typename std::enable_if::value, Type_>::type operator&(const Math::Vector& other) const { \ + return Math::Vector::andInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template typename std::enable_if::value, Type&>::type operator|=(const Math::Vector& other) { \ + template typename std::enable_if::value, Type_&>::type operator|=(const Math::Vector& other) { \ Math::Vector::operator|=(other); \ return *this; \ } \ - template typename std::enable_if::value, Type>::type operator|(const Math::Vector& other) const { \ - return Math::Vector::operator|(other); \ + template constexpr typename std::enable_if::value, Type_>::type operator|(const Math::Vector& other) const { \ + return Math::Vector::orInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template typename std::enable_if::value, Type&>::type operator^=(const Math::Vector& other) { \ + template typename std::enable_if::value, Type_&>::type operator^=(const Math::Vector& other) { \ Math::Vector::operator^=(other); \ return *this; \ } \ - template typename std::enable_if::value, Type>::type operator^(const Math::Vector& other) const { \ - return Math::Vector::operator^(other); \ + template constexpr typename std::enable_if::value, Type_>::type operator^(const Math::Vector& other) const { \ + return Math::Vector::xorInternal(other, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template typename std::enable_if::value, Type&>::type operator<<=(typename std::common_type::type shift) { \ + template typename std::enable_if::value, Type_&>::type operator<<=(typename std::common_type::type shift) { \ Math::Vector::operator<<=(shift); \ return *this; \ } \ - template typename std::enable_if::value, Type>::type operator<<(typename std::common_type::type shift) const { \ - return Math::Vector::operator<<(shift); \ + template constexpr typename std::enable_if::value, Type_>::type operator<<(typename std::common_type::type shift) const { \ + return Math::Vector::shiftLeftInternal(shift, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ - template typename std::enable_if::value, Type&>::type operator>>=(typename std::common_type::type shift) { \ + template typename std::enable_if::value, Type_&>::type operator>>=(typename std::common_type::type shift) { \ Math::Vector::operator>>=(shift); \ return *this; \ } \ - template typename std::enable_if::value, Type>::type operator>>(typename std::common_type::type shift) const { \ - return Math::Vector::operator>>(shift); \ + template constexpr typename std::enable_if::value, Type_>::type operator>>(typename std::common_type::type shift) const { \ + return Math::Vector::shiftRightInternal(shift, typename Containers::Implementation::GenerateSequence::Type{}); \ } \ \ - template typename std::enable_if::value, Type>::type normalized() const { \ + template typename std::enable_if::value, Type_>::type normalized() const { \ return Math::Vector::normalized(); \ } \ - template typename std::enable_if::value, Type>::type resized(T length) const { \ + template typename std::enable_if::value, Type_>::type resized(T length) const { \ return Math::Vector::resized(length); \ } \ - template typename std::enable_if::value, Type>::type projected(const Math::Vector& other) const { \ + template typename std::enable_if::value, Type_>::type projected(const Math::Vector& other) const { \ return Math::Vector::projected(other); \ } \ - template typename std::enable_if::value, Type>::type projectedOntoNormalized(const Math::Vector& other) const { \ + template typename std::enable_if::value, Type_>::type projectedOntoNormalized(const Math::Vector& other) const { \ return Math::Vector::projectedOntoNormalized(other); \ } \ - constexpr Type flipped() const { \ + constexpr Type_ flipped() const { \ return Math::Vector::flipped(); \ } #endif @@ -1455,12 +1510,12 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>& to return a correct subtype. See VectorTest::multiplyDivideIntegral(), VectorTest::subclass() and corresponding cases in Vector2Test, Vector3Test, Vector4Test and ColorTest for regression tests. */ -template inline typename std::enable_if::value && std::is_floating_point::value, Vector>::type operator*(FloatingPoint scalar, const Vector& vector) { +template constexpr typename std::enable_if::value && std::is_floating_point::value, Vector>::type operator*(FloatingPoint scalar, const Vector& vector) { return vector*scalar; } #define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \ - template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint scalar, const Type& vector) { \ + template constexpr typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint scalar, const Type& vector) { \ return vector*scalar; \ } #endif @@ -1501,21 +1556,6 @@ template inline BitVector Vector::oper return out; } -template -#ifdef DOXYGEN_GENERATING_OUTPUT -inline Vector -#else -template inline typename std::enable_if::value, Vector>::type -#endif -Vector::operator-() const { - Vector out; - - for(std::size_t i = 0; i != size; ++i) - out._data[i] = -_data[i]; - - return out; -} - template #ifdef DOXYGEN_GENERATING_OUTPUT inline Vector