C++11: VectorT now also accepts non-arithmetic types as Scalar.

This commit is contained in:
Hans-Christian Ebke
2015-11-19 15:20:41 +01:00
parent 4c36fcfee8
commit 580e5526d8
2 changed files with 88 additions and 18 deletions

View File

@@ -138,11 +138,15 @@ class VectorT {
* Only for 4-component vectors with division operator on their * Only for 4-component vectors with division operator on their
* Scalar: Dehomogenization. * Scalar: Dehomogenization.
*/ */
template<int D = DIM, template<typename S = Scalar, int D = DIM>
typename = typename std::enable_if<D == DIM>::type, auto homogenized() const ->
typename = decltype(values_[0]/values_[3])> typename std::enable_if<D == 4,
typename std::enable_if<D==4, VectorT>::type VectorT<decltype(std::declval<S>()/std::declval<S>()), DIM>>::type {
homogenized() const { static_assert(D == DIM, "D and DIM need to be identical. (Never "
"override the default template arguments.)");
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return VectorT( return VectorT(
values_[0]/values_[3], values_[0]/values_[3],
values_[1]/values_[3], values_[1]/values_[3],
@@ -383,7 +387,11 @@ class VectorT {
//@{ //@{
/// compute squared euclidean norm /// compute squared euclidean norm
decltype(values_[0] * values_[0]) sqrnorm() const { template<typename S = Scalar>
decltype(std::declval<S>() * std::declval<S>()) sqrnorm() const {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
typedef decltype(values_[0] * values_[0]) RESULT; typedef decltype(values_[0] * values_[0]) RESULT;
return std::accumulate(values_.cbegin() + 1, values_.cend(), return std::accumulate(values_.cbegin() + 1, values_.cend(),
values_[0] * values_[0], values_[0] * values_[0],
@@ -391,38 +399,58 @@ class VectorT {
} }
/// compute euclidean norm /// compute euclidean norm
auto norm() const -> decltype(std::sqrt(this->sqrnorm())) { template<typename S = Scalar>
auto norm() const ->
decltype(std::sqrt(std::declval<VectorT<S, DIM>>().sqrnorm())) {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return std::sqrt(sqrnorm()); return std::sqrt(sqrnorm());
} }
auto length() const -> decltype(this->norm()) { template<typename S = Scalar>
auto length() const ->
decltype(std::declval<VectorT<S, DIM>>().norm()) {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return norm(); return norm();
} }
/** normalize vector, return normalized vector /** normalize vector, return normalized vector
*/ */
vector_type& normalize() { template<typename S = Scalar>
*this /= norm(); auto normalize() ->
return *this; decltype(*this /= std::declval<VectorT<S, DIM>>().norm()) {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return *this /= norm();
} }
/** return normalized vector /** return normalized vector
*/ */
auto normalized() const -> decltype((*this) / this->norm()) { template<typename S = Scalar>
auto normalized() const ->
decltype(*this / std::declval<VectorT<S, DIM>>().norm()) {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return *this / norm(); return *this / norm();
} }
/** normalize vector, return normalized vector and avoids div by zero /** normalize vector, return normalized vector and avoids div by zero
*/ */
template<typename S = typename std::result_of< template<typename S = Scalar>
decltype(&VectorT::norm)(VectorT)>::type>
typename std::enable_if< typename std::enable_if<
sizeof(static_cast<S>(0)) >= 0, sizeof(decltype(
static_cast<S>(0),
std::declval<VectorT<S, DIM>>().norm())) >= 0,
vector_type&>::type vector_type&>::type
normalize_cond() { normalize_cond() {
static_assert(sizeof(static_cast<decltype(norm())>(0)) >= 0, static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"normalize_cond() only works with Scalar types that can " "to be the same type. (Never override the default template "
"be statically casted from 0."); "arguments.)");
auto n = norm(); auto n = norm();
if (n != static_cast<decltype(norm())>(0)) { if (n != static_cast<decltype(norm())>(0)) {
*this /= n; *this /= n;

View File

@@ -176,4 +176,46 @@ TEST_F(OpenMeshVectorTest, size_dim) {
EXPECT_EQ(2, v2i.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<C, 3> x, y;
x = std::move(y);
EXPECT_EQ(3, C::copy_ass);
EXPECT_EQ(0, C::copy_con);
// Test move constructing.
OpenMesh::VectorT<C, 3> z(std::move(x));
EXPECT_EQ(3, C::copy_ass);
EXPECT_EQ(3, C::copy_con);
}
} }