From 580e5526d8ec9ad80cdb278e6e586ae74344f007 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 15:20:41 +0100 Subject: [PATCH] C++11: VectorT now also accepts non-arithmetic types as Scalar. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 64 ++++++++++++++++++------- src/Unittests/unittests_vector_type.cc | 42 ++++++++++++++++ 2 files changed, 88 insertions(+), 18 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 978e5408..e29f5013 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -138,11 +138,15 @@ class VectorT { * Only for 4-component vectors with division operator on their * Scalar: Dehomogenization. */ - template::type, - typename = decltype(values_[0]/values_[3])> - typename std::enable_if::type - homogenized() const { + template + auto homogenized() const -> + typename std::enable_if()/std::declval()), DIM>>::type { + static_assert(D == DIM, "D and DIM need to be identical. (Never " + "override the default template arguments.)"); + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); return VectorT( values_[0]/values_[3], values_[1]/values_[3], @@ -383,7 +387,11 @@ class VectorT { //@{ /// compute squared euclidean norm - decltype(values_[0] * values_[0]) sqrnorm() const { + template + decltype(std::declval() * std::declval()) sqrnorm() const { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); typedef decltype(values_[0] * values_[0]) RESULT; return std::accumulate(values_.cbegin() + 1, values_.cend(), values_[0] * values_[0], @@ -391,38 +399,58 @@ class VectorT { } /// compute euclidean norm - auto norm() const -> decltype(std::sqrt(this->sqrnorm())) { + template + auto norm() const -> + decltype(std::sqrt(std::declval>().sqrnorm())) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); return std::sqrt(sqrnorm()); } - auto length() const -> decltype(this->norm()) { + template + auto length() const -> + decltype(std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); return norm(); } /** normalize vector, return normalized vector */ - vector_type& normalize() { - *this /= norm(); - return *this; + template + auto normalize() -> + decltype(*this /= std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return *this /= norm(); } /** return normalized vector */ - auto normalized() const -> decltype((*this) / this->norm()) { + template + auto normalized() const -> + decltype(*this / std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); return *this / norm(); } /** normalize vector, return normalized vector and avoids div by zero */ - template::type> + template typename std::enable_if< - sizeof(static_cast(0)) >= 0, + sizeof(decltype( + static_cast(0), + std::declval>().norm())) >= 0, vector_type&>::type normalize_cond() { - static_assert(sizeof(static_cast(0)) >= 0, - "normalize_cond() only works with Scalar types that can " - "be statically casted from 0."); + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); auto n = norm(); if (n != static_cast(0)) { *this /= n; diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index 762998dd..a5882431 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -176,4 +176,46 @@ TEST_F(OpenMeshVectorTest, size_dim) { EXPECT_EQ(2, v2i.dim()); } +namespace { +class C { + public: + C() {} + C(const C &rhs) { ADD_FAILURE() << "Copy constructor used."; } + C(C &&rhs) { ++copy_con; } + C &operator= (const C &rhs) { + ADD_FAILURE() << "Copy assignemnt used."; + return *this; + } + C &operator= (C &&rhs) { ++copy_ass; return *this; } + + static int copy_con; + static int copy_ass; +}; + +int C::copy_con = 0; +int C::copy_ass = 0; +} + +/** + * Checks two things: + * 1) Whether VectorT works with a non-arithmetic type. + * 2) Whether move construction and assignment works. + */ +TEST_F(OpenMeshVectorTest, move_constructor_assignment) { + + C::copy_con = 0; + C::copy_ass = 0; + + // Test move assigning. + OpenMesh::VectorT x, y; + x = std::move(y); + EXPECT_EQ(3, C::copy_ass); + EXPECT_EQ(0, C::copy_con); + + // Test move constructing. + OpenMesh::VectorT z(std::move(x)); + EXPECT_EQ(3, C::copy_ass); + EXPECT_EQ(3, C::copy_con); +} + }