2
votes

I'm trying to create a class of fixed size vectors, to use mostly for geometrical purposes, where vector length doesn't change:

template<typename T, int n>
class FixedVector
{
private:
    T m_rV[n]; // this is the only data member
     public:
              // class function members
              ...
}

This would have the advantage of compiler checking for operations with vectors of incompatible size.

I'm having problems when trying to build an operator* for this class (note: it is not a member). This operator should multiply the vector by a scalar, like this 3*[1,2,3]=[3,6,9].

template<typename T, int n>
FixedVector<T,n> operator*(const T   &rX, const FixedVector<T,n> &cV) const
{   typename std::pointer_to_binary_function<T,T,T> op=(util::times<T>);
    FixedVector<T,n> cT(cV, std::bind1st(op, rX));
    return cT;
}

where times is the multiplication function of a scalar member of the vector

template<typename T>
inline T times(const T &t1, const T &t2)
{   return t1*t2;
}

the code for the constructor in line 4 is

template<typename T, int n>
FixedVector<T,n>::FixedVector(const T rV[n], T (*f)(const T &)) 
{   util::copy(m_rV, rV, n, f);
}

and pointer_to_binary_function and bind1st are STL functions from the header (Those who can help should know this already).

I'm getting the following compiler error in Visual Studio 2005 when calling

    util::FixedVector<int,4> x; 3*x;

:

fixed_vector.hpp(212) : error 2440:
        'initializing' : cannot convert from 'T (__cdecl *)(const T &,const T &)'
         to 'std::pointer_to_binary_function<_Arg1,_Arg2,_Result>'
with
[
       _Arg1=int,
        _Arg2=int,
        _Result=int
    ]
    No constructor could take the source type, or constructor overload resolution was ambiguous
    testproject.cpp(18) : see reference to function template instantiation 'util::FixedVector<T,n> util::operator *<T,4>(const T &,const util::FixedVector<T,n> &)' being compiled
   with
    [
        T=int,
        n=4
    ]

It appears that typename std::pointer_to_binary_function is correctly instantiated to std::pointer_to_binary_function However, times still remains to its basic signature: 'T (__cdecl *)(const T &,const T &)


--- AFTER SOME EDITING ----------------------------------------------------------------

It was indicated to me that a function that my constructor requests a plain function as parameter: T (*)(const T &t1, const T &t2) and that STL functional objects won't be accepted. The link here STL for_each served as a guide on how to do the corrections.

I started to changing from the util::copy function, called by constructor.

From: template void copy(T *dst, const T *src, size_t n, T (*f)(const T &)) { for (; n>0; n--, dst++, src++) { *dst = f(*src); } }

it became

    template<typename T, typename Function>
void copy(T *dst, const T *src, size_t n, Function f)
{   for (; n>0; n--, dst++, src++)
    {   *dst = (*f)(*src);
}   }

Then, the constructor itself was templated. From:

template<typename T, int n>
FixedVector<T,n>::FixedVector(const T rV[n], T (*f)(const T &)) 
{   util::copy(m_rV, rV, n, f);
}

it is now

     template<typename T, int n>
template<class Function>
FixedVector<T,n>::FixedVector(const FixedVector<T,n> &cV, Function f)
{   util::copy(m_rV, cV.m_rV, n, f);
}

Also added some consts to template instantiation parameters:

template<typename T, int n>
FixedVector<T,n> operator*(const T   &rX, const FixedVector<T,n> &cV)
{   typename std::pointer_to_binary_function<const T,const T,T> op(times<T>);
    FixedVector<T,n> cT(cV, std::bind1st(op, rX));
    return cT;
}

But I still get the same error (only that T has been replaced by const T; note that adding a & to indicate reference (const T&) will trigger an error and it seems that templates have problems with this, Boost and TR1 creating special solutions to deal with this - see Wikipedia TR1 reference wrapper).

The exact line of the error is this:

typename std::pointer_to_binary_function<const T,const T,T> op(times<T>);

So I don't even reach the constructor.

I'd be very grateful with some extra ideas.

2
To explicitly state the question: How could this problem be solved?Tetelu
Why not use std::array<T, N>? You can make the dot product into a non-member function.Kerrek SB
What's the line FixedVector<T,n> cT(cV, std::bind1st(op, rX)); supposed to do? Did you implement such a constructor?Kerrek SB
Thank you Kerrek for your prompt response. I've edited the message with code of the constructor. Regarding the use of std::array<T, N>, I'll take a look on it. But I'm still interested in understanding what the problem of this code is. I was eventually planning to use it for vectors whose elements are no stored contiguously in memory, like the columns of a matrix, and I'm not sure if STL has everything I need (well, I'm not an absolute expert in STL).Tetelu
Right. Not sure if bind1st is convertible to a function pointer; why don't you make the constructor argument a unary_function?Kerrek SB

2 Answers

2
votes

Your function util::times has the signature:

T times(const T&, const T&)

but in this line:

typename std::pointer_to_binary_function<T,T,T> op=(util::times<T>);

the constructor of std::pointer_to_binary_function is expecting:

T times(T, T)

You can fix that by using const T& as argument template parameters:

typename std::pointer_to_binary_function<const T&, const T&, T> op(util::times<T>);

Note that I removed the = to use explicit constructor notation here. At least in (my) GCC, the assignment syntax is rejected by the compiler.

Since you are creating a binary functor that does multiplication, instead of the custom times function and functor wrapper, you could directly use std::multiplies to achieve the same:

std::multiplies<T> op;

Note that in your next line,

FixedVector<T,n> cT(cV, std::bind1st(op, rX));

you are calling a constructor that takes a FixedVector<T, n> as first argument, and a unary functor as second. This is not compatible with the constructor code you posted:

template<typename T, int n>
FixedVector<T,n>::FixedVector(const T rV[n], T (*f)(const T &)) 
{   util::copy(m_rV, rV, n, f);
}

since this one takes a plain array and a function pointer.

1
votes
template<typename T, int n>
FixedVector<T,n>::FixedVector(const T rV[n], T (*f)(const T &)) 
{   util::copy(m_rV, rV, n, f);
}

You cannot convert to a function pointer from any functional object with state, and even then, only stateless C++0x lambdas. You must take a template functional object, or a polymorphic one like function, found in Boost, TR1 and C++0x.

Besides, this is incredibly obscure. Why not just do a regular multiply? It would be far simpler than this approach.