указание типа члена класса в шаблонной функции - PullRequest
1 голос
/ 31 мая 2011

У меня есть эта шаблонная функция:

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);
}

, но я хочу избегать принудительного принудительного возвращения типа возврата к double все время - P :: x и P :: y также могут быть целыми числами,и мне нужна эта функция в обеих ситуациях.Есть ли способ указать тип x и y, что-то вроде этого?

//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: Мой компилятор VC2005

edit2: извините, но не могу упомянуть: к сожалению я могу 't изменить реализацию структур для P;один из типов точек, с которыми я имею дело, это CPoint MFC / ATL, которые жестко закодированы как { long x; long y; }.

Ответы [ 4 ]

7 голосов
/ 31 мая 2011

Компилятор не может определить тип возвращаемого значения шаблона функции из аргумента функции. Вывод типа выполняется только с аргументами функции.

В C ++ 03 вы можете определить typedef в своем классе как:

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!
};

А затем вы должны переписать свою функцию как:

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);
}

Обратите внимание на тип возвращаемого значения, это зависимый тип. Его:

typename P::value_type

Здесь необходимо ключевое слово typename.


Хорошо, поскольку вы сказали, что не можете изменять свои структуры, тогда вместо этого вы можете использовать черты. Вот как это можно сделать:

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!
};

И ваш шаблон функции будет выглядеть так:

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);
}

Обратите внимание на тип возврата; сейчас немного по-другому:

typename PTraits<P>::value_type

Опять же, value_type является зависимым именем, поэтому необходимо ключевое слово typename.

Обратите внимание, что вы должны специализировать PTraits<> для каждого типа, который вы передаете шаблону функции, как я сделал.

3 голосов
/ 31 мая 2011

Мне нравится использовать подход стиля черт:

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);
}

Если вы хотите, чтобы значение по умолчанию удваивалось, тогда вы просто добавляете typedef double ReturnType; к исходному шаблону.

2 голосов
/ 31 мая 2011

Если вы используете Visual Studio 2010 или GCC 4.5+, вы можете использовать форму завершающего возврата:

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

Благодаря decltype мы автоматически получаем правильный тип возврата. Кроме того, вычисление все еще выполняется только один раз в теле, а не в конце.

0 голосов
/ 31 мая 2011

Проверьте возвращаемое значение. Введите тип переменной члена x / y. Возможно, вы не вернетесь, поэтому введите T.

...