表达式模板:错误C2784'无法推断模板参数'

时间:2015-03-03 16:30:31

标签: c++ templates inheritance expression-templates

我正在使用一个使用表达式模板的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,代码会进行编译,一切正常,包括lengthnormalize的版本被叫。但是,如果我将成员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称为作为VectorExpression的独立函数或作为Expression的继承成员,类似于使用它的方式length,编译并正常工作。 normalize的独立版本也可以正常运行。我将normalize定义为班级成员有什么问题?

谢谢!

1 个答案:

答案 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>,所以我不明白为什么我必须进行此更改。