Проблем с указатели към методи и шаблони, 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 указателя, сочещи към getters.

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++.

Стандартът 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