martin_ljchan
martin_ljchan

Reputation: 1063

specifying type of a class member in template function

I have this template function:

template <class P>
double Determinant(const P & a, const P & b, const P & c) {
    return  (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}

but I want to avoid forcing the return type to double all the time -- P::x and P::y could be ints too, and I need this function in both situations. Is there a way to specify the type of x and y, something like this?

//doesn't compile; can't deduce template argument for T
template <typename T, class P>
T Determinant(const P & a, const P & b, const P & c) {
    return  (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}

edit: My compiler is VC2005

edit2: sorry to forget to mention: Unfortunately I can't modify the implementation of the structs for P; one of the point types I deal with is MFC/ATL's CPoint, which are hard-coded as { long x; long y; }.

Upvotes: 1

Views: 1573

Answers (4)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361732

Compiler cannot deduce return-type of function template, from function argument. Type deduction is done with function arguments only.

In C++03, you can define typedef in your class as:

struct A //suppose A is going to be type argument to your function template
{
   int x, y;     //I'm assuming type of x and y is same!
   typedef int value_type; //type of x and y!
};

And then you've to re-write your function as:

template <class P>
typename P::value_type Determinant(const P & a, const P & b, const P & c) {
    return  (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}

Notice the return-type now, its a dependent type. Its :

typename P::value_type

The keyword typename is required here.


Alright, as you said you can't modify your structs, then you can use traits instead. Here is how this can be done:

template<typename T> struct PTraits;

//Suppose this is your type which you can't modify
struct A //A is going to be type argument to your function template
{
   long x, y; 
};

//specialization: defining traits for struct A
template<>
struct PTraits<A>
{
    typedef long value_type; //since type of A::x and A::y is long!
};

And your function template would look like this:

template <class P>
typename PTraits<P>::value_type Determinant(const P & a, const P & b, const P & c) {
    return  (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}

Notice the return-type; its slightly different now:

typename PTraits<P>::value_type

Again, value_type is a dependent name, so the keyword typename is required.

Note that you've to specialize PTraits<> for each type which you pass to the function template, as I did.

Upvotes: 7

Michael Anderson
Michael Anderson

Reputation: 73590

I like to use a traits style approach to this:

template<typename T> struct DeterminantReturnInfo {};  
template<> struct DeterminantReturnInfo<MyType> { typedef MyOtherType ReturnType; }

template< typename T >
typename DeterminantReturnInfo<T>::ReturnType Determinant( const P & a, const P & B, const P & c)
{
  return  (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
}

If you want it to default to double then you just add typedef double ReturnType; to the initial template.

Upvotes: 3

Satbir
Satbir

Reputation: 6506

Check your return Type its of type member variable x/y . You might not returning so type T.

Upvotes: 0

Xeo
Xeo

Reputation: 131877

If you're using Visual Studio 2010 or GCC 4.5+, you can use the trailing return type form:

template<class P>
auto fun(const P& a) -> decltype(a.x + a.y){
  return a.x + a.y;
}

Thanks to decltype we automatically get the right return type. Also, the computation is still only done once in the body, not in the trailing return.

Upvotes: 2

Related Questions