Проблема с указателями на методы и шаблоны, C++

Есть 2 класса шаблонов A и B, имеющие 2 закрытых члена a1, a2 и b1, b2.

template <typename T>
class A
{
private:
    T a1, a2;

public:
    T getA1 () const {return a1;}
    T getA2 () const {return a2;}

};


template <typename T>
class B
{
private:
    T b1, b2;

public:
    T getB1 () const {return b1;}
    T getB2 () const {return b2;}

};

В классе Test нужно 2 указателя на геттеры.

class Test
{
  private:
    template <typename T>
    static T ( *getFirst ) ();

    template <typename T>
    static T ( *getSecond ) ();

}


template <typename T>
T ( * Test::getFirst ) ()  =  &A<T>::getA1; //Pointer to getA1, error

template <typename T>
T ( * Test::getSecond ) ()  =  &B<T>::getB2; //Pointer to getB2, error

int main
{
   A <double> a;
   B <double> b;

   double c = a.getFirst + b.getSecond;
}

T представляет основные типы данных... Возможно ли реализовать этот код без специализации (т.е. указатели на члены шаблона класса) или эти "указатели" должны быть специализированными? Спасибо за любые примеры...


person CrocodileDundee    schedule 12.02.2011    source источник
comment
Я пытался составить ответ, но потерпел неудачу по одной причине: я не понимаю, что вы собираетесь делать со своим классным тестом. Вы предоставляете его определение, в котором есть ошибки, но вы нигде его не используете. Способ исправления этих ошибок во многом зависит от того, как вы планируете его использовать. Некоторые из приведенных ниже ответов могут оказаться для вас полезными, но для того, чтобы получить правильный ответ, вам необходимо привести пример использования Test.   -  person Sergei Tachenov    schedule 12.02.2011


Ответы (4)


Вы занимаетесь незаконными вещами. Видеть это,

template <typename T>
static T ( *getFirst ) ();

Здесь вы пытаетесь определить указатель функции шаблона, что недопустимо в C++.

Стандарт С++ говорит в $ 14/1,

Шаблон определяет семейство классов или функций.

Обратите внимание, что здесь не говорится, что «шаблон определяет семейство классов, функций или указателей на функции". Итак, вы пытаетесь определить "семейство указателей на функции" с помощью шаблона, что не разрешено.


Если вам нужен указатель функции, вы можете сделать что-то вроде этого,

template <class T>
struct A
{
   static T (*FunctionPointer)(); //function pointer
};

struct B
{
   template <class T>
   static T Function(); //static function, not function pointer
};

int (*A<double>::FunctionPointer)() = &B::Function<double>;

Еще лучшая альтернатива: используйте объект-функцию. :-)

person Nawaz    schedule 12.02.2011
comment
Ок, спасибо... Как будет выглядеть код, когда функция не будет статической? Могу я также попросить вас привести краткий пример использования функциональных объектов в этом случае? - person CrocodileDundee; 12.02.2011

Короче говоря, это невозможно.

Во-первых, вы не можете объявить указатель на функцию шаблона, только указатель на конкретную функцию. Во-вторых, вы пытались объявить указатель на свободную функцию, но A::getA1 является функцией-членом с неявным аргументом this, поэтому семантика не совпадает.

Вы можете сделать что-то вроде этого:

template <typename T>
struct A
{
    static T get() { return T() };
};

template <typename T>
struct Holder
{
    typedef T(A<T>::*F_ptr)();
    static F_ptr f_ptr;
};


template <typename T>
typename Holder<T>::F_ptr Holder<T>::f_ptr  =  &A<T>::get;

сохранить указатель на функцию шаблона как член класса шаблона

person Andriy Tylychko    schedule 12.02.2011

Линия:

template <typename T>
T (*Test::getFirst)() = &A<T>::getA1; //Pointer to getA1, error

Имеет две проблемы: первая состоит в том, что &A<T>::getA1 имеет тип T (A::*)()const, а getFirst имеет тип T (*)(). Они несовместимы, поскольку первый является указателем на функцию-член, а второй — нет.

Вторая проблема со строкой заключается в том, что создаваемые объекты будут отличаться только типом возвращаемого значения. Точно так же, как вы не можете вручную объявить и double (A::*getFirst)()const, и char (A::*getFirst)()const, вы также не можете создать шаблон, который бы автоматически объявлял их обоих.

Линия:

double c = a.getFirst + b.getSecond;

Имеет собственный набор проблем, которые могут относиться или не относиться к рассматриваемой проблеме.

Извините за этот "не ответ". возможно, если бы вы больше говорили о том, чего вы пытаетесь достичь, а не о том, как вы пытаетесь этого добиться, мы сможем помочь.

person Daniel T.    schedule 12.02.2011

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

// This is one template class A with two getters
template <typename T>
class A
{
private:
    T a1, a2;

public:
    T getA1 () const {return a1;}
    T getA2 () const {return a2;}
};

// This is another unrelated template class, with two other getters
template <typename T>
class B
{
private:
    T b1, b2;

public:
    T getB1 () const {return b1;}
    T getB2 () const {return b2;}
};

// These are declarations of generic "getFirst" and "getSecond"
template<typename T1, typename T2>
T1 getFirst(const T2& t);

template<class T1, class T2>
T1 getSecond(const T2& t);

// Here I'm specializing getFirst/getSecond for the A template
template<class X>
double getFirst(const A<X>& a)  { return a.getA1(); }

template<class X>
double getSecond(const A<X>& a) { return a.getA2(); }

// Here I'm doing the same for the B template
template<class X>
double getFirst(const B<X>& b)  { return b.getB1(); }

template<class X>
double getSecond(const B<X>& b) { return b.getB2(); }

// Now I can use getFirst/getSecond with either A or B
int main(int argc, const char *argv[])
{
   A<double> a;
   B<double> b;
   double c = getFirst(a) + getSecond(b);
   return 0;
}
person 6502    schedule 12.02.2011