Can't correctly instantiate template when using C++ functional library
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 开发者_Python百科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.
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.
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.
精彩评论