我正在使用一个使用表达式模板的vector类。我有以下(简化)代码。在“Vector.h”中:
#include <cmath>
#include <iostream>
#include <limits>
#include <type_traits>
#define NULLVAL(a) (*((a*) 0))
namespace VectorExpression {
template <typename E, typename R> class Expression;
template <typename E, typename R, typename S, typename Op> class ScalarBinary;
template <tyepname E1, typename R1, typename E2, typename R2, typename Op> class VectorBinary;
template <typename T1, typename T2> struct Div;
template <typename T1, typename T2> struct Div2;
template <typename T> class Vector;
};
template <typename E, typename R, typename S>
typename std::enable_if<std::is_arithmetic<S>::value, VectorExpression::ScalarBinary<E, R, S, VectorExpression::Div<R, S>>>::type
operator/(const VectorExpression::Expression<E, R> &expr, S a) // LINE #136
{
return ( VectorExpression::ScalarBinary<E, R, S, VectorExpression::Div<R, S>>(expr, a) );
}
template <typename E, typename R, typename S>
typename std::enable_if<std::is_arithmetic<S>::value, VectorExpression::ScalarBinary<E, R, S, VectorExpression::Div2<R, S>>>::type
operator/(S a, const VectorExpression::Expression<E, R> &expr) // LINE #143
{
return ( VectorExpression::ScalarBinary<E, R, S, VectorExpression::Div2<R, S>>(expr, a) );
}
template <typename E1, typename R1, typename E2, typename R2>
auto operator/(const VectorExpression::Expression<E1, R1> &expr1, const VectorExpression::Expression<E2, R2> &expr2) -> VectorExpression::VectorBinary<E1, R1, E2, R2, VectorExpression::Div<R1, R2>> // LINE #174
{
return ( VectorExpression::VectorBinary<E1, R1, E2, R2, VectorExpression::Div<R1,R2>>(expr1, expr2) );
}
// length #1
template <typename E, typename R>
double length(const VectorExpression::Expression<E, R> &expr)
{
return ( sqrt( pow(expr.x(), 2) + pow(expr.y(), 2) + pow(expr.z(), 2) );
}
// length #2
template <typename T>
double length(const VectorExpression::Expression<Vector<T>, T> &expr) // length #2
{
return ( sqrt( expr.x() * expr.x() + expr.y() * expr.y() + expr.z() * expr.z() );
}
// normalize #1
template <typename E, typename R>
auto normalize(const VectorExpression::Expression<E, R> &expr) -> decltype( NULLVAL(Vector<double>) / NULLVAL(double) )
{
Vector<double> v(expr);
return ( v / v.length() );
}
// normalize #2
template <typename T>
auto normalize(const VectorExpression::Expression<Vector<T>, T> &expr) -> decltype( NULLVAL(Vector<double>) / NULLVAL(double) )
{
return ( static_cast<Vector<double>>(expr) / expr.length() );
}
namespace VectorExpression {
template <typename E, typename R>
class Expression {
protected:
Expression() { }
public:
typedef R value_type;
value_type x() const
{
return ( static_cast<const E&>(*this).x() );
}
value_type y() const
{
return ( static_cast<const E&>(*this).y() );
}
value_type z() const
{
return ( static_cast<const E&>(*this).z() );
}
double length() const
{
return ( ::length(static_cast<const E&>(*this)) );
}
auto normalize() -> decltype( NULLVAL(Vector<double>) / NULLVAL(double) ) // LINE #323
{
return ( ::normalize(static_cast<const E&>(*this)) );
}
};
template <typename E, typename R, typename S, typename Op>
class ScalarBinary : public Expression<ScalarBinary<E, R, S, Op>, typename Op::value_type> {
private:
const E& v;
S a;
public:
ScalarBinary(const Expression<E, R> &expr, S scalar) : v(expr), a(scalar) { }
value_type x() const
{
return ( Op::apply( v.x(), a ) );
}
value_type y() const
{
return ( Op::apply( v.y(), a ) );
}
value_type z() const
{
return ( Op::apply( v.z(), a ) );
}
};
template <typename E1, typename R1, typename E2, typename R2, typename Op>
class VectorBinary : public Expression<VectorBinary<E1, R1, E2, R2, Op>, typename Op::value_type> {
private:
const E1 &v1;
const E2 &v2;
public:
VectorBinary(const Expression<E1, R1> &expr1, const Expression<E2, R2> &expr2) : v1(expr1), v2(expr2) { }
value_type x() const
{
return ( Op::apply( v1.x(), v2.x() ) );
}
value_type y() const
{
return ( Op::apply( v1.y(), v2.y() ) );
}
value_type z() const
{
return ( Op::apply( v1.z(), v2.z() ) );
}
};
template <typename T1, typename T2>
struct Div {
typedef decltype( NULLVAL(T1) / NULLVAL(T2) ) value_type;
static value_type apply( T1 x1, T2 x2 ) { return ( x1 / x2 ); }
};
template <typename T1, typename T2>
struct Div2 {
typedef decltype( NULLVAL(T2) / NULLVAL(T1) ) value_type;
static value_type apply( T1 x1, T2 x2 ) { return ( x2 / x1 ); }
};
template <typename T>
class Vector : public Expression<Vector<T>, T> { // LINE #578
private:
T _x, _y, _z;
public:
template <typename U1, typename U2, typename U3>
Vector(U1 X, U2 Y, U3 Z) : _x(static_cast<T>(X)), _y(static_cast<T>(Y)), _z(static_cast<T>(Z)) { }
template <typename E, typename R>
Vector(const Expression<E, R> &expr) : _x(static_cast<T>(expr.x())), _y(static_cast<T>(expr.y())), _z(static_cast<T>(expr.z())) { }
value_type x() const
{
return ( this->_x );
}
value_type y() const
{
return ( this->_y );
}
value_type z() const
{
return ( this->_z );
}
};
};
然后,在“main.cpp”中:
#include "Vector.h"
int main(int argc, char *argv[])
{
Vector<double> a(0.5, 1.5, 2.5), b; // LINE #12
double c;
c = length(a); // calls length #1
c = length(a/2.0); // calls length #2
a.length(); // calls length #1
(a/2).length(); // calls length #2
b = normalize(a); // calls normalize #1
b = normalize(a/2.0); // calls normalize #2
return ( 0 );
}
现在,如果我在课程normalize
中注释掉该成员Expression
,代码会进行编译,一切正常,包括length
和normalize
的版本被叫。但是,如果我将成员normalize
取消注释,我会收到以下编译器错误:
vector.h(323): error C2784: 'VectorExpression::VectorBinary<E1,R1,E2,R2,VectorExpression::Div<R1,R2>> operator /(const VectorExpression::_Expression<E,R> &,const VectorExpression::_Expression<E2,R2> &)' : could not deduce template argument for 'const VectorExpression::_Expression<E,R> &' from 'VectorExpression::Vector<T>'
with
[
T=double
]
vector.h(174) : see declaration of 'operator /'
vector.h(384) : see reference to class template instantiation 'VectorExpression::_Expression<E,R>' being compiled
with
[
E=VectorExpression::Vector<double>,
R=double
]
vector.h(578) : see reference to class template instantiation 'VectorExpression::Expression<E,R>' being compiled
with
[
E=VectorExpression::Vector<double>,
R=double
]
main.cpp(12) : see reference to class template instantiation 'VectorExpression::Vector<T>' being compiled
with
[
T=double
]
vector.h(323): error C2784: 'std::enable_if<std::is_arithmetic<S>::value,VectorExpression::ScalarBinary<E,R,S,VectorExpression::Div2<R,S>>>::type operator /(S,const VectorExpression::_Expression<E,R> &)' : could not deduce template argument for 'const VectorExpression::_Expression<E,R> &' from 'double'
vector.h(143) : see declaration of 'operator /'
vector.h(323): error C2784: 'std::enable_if<std::is_arithmetic<S>::value,VectorExpression::ScalarBinary<E,R,S,VectorExpression::Div<R,S>>>::type operator /(const VectorExpression::_Expression<E,R> &,S)' : could not deduce template argument for 'const VectorExpression::_Expression<E,R> &' from 'VectorExpression::Vector<T>'
with
[
T=double
]
vector.h(136) : see declaration of 'operator /'
vector.h(323): error C2676: binary '/' : 'VectorExpression::Vector<T>' does not define this operator or a conversion to a type acceptable to the predefined operator
with
[
T=double
]
我希望能够将normalize称为作为Vector
或Expression
的独立函数或作为Expression
的继承成员,类似于使用它的方式length
,编译并正常工作。 normalize
的独立版本也可以正常运行。我将normalize
定义为班级成员有什么问题?
谢谢!
答案 0 :(得分:0)
如果我改变
,它会编译并正常工作auto normalize() -> decltype( NULLVAL(Vector<double>) / NULLVAL(double) )
在班级Expression
中
auto normalize() -> decltype( (*((Expression<Vector<double>,double>*) 0)) / NULLVAL(double) )
但是,我不明白为什么这是必要的。 normalize的独立声明使用以前的decltype
样式并且正常工作,而Vector<double>
继承自Expression<Vector<double>,double>
,所以我不明白为什么我必须进行此更改。