2012-02-16 2 views
3

я имел ситуацию очень много сродни этому:Pass указатель функции в шаблон

#include <iostream> 

template<class B> 
class A 
{ 
public: 
    A<B>(const B& b) : m_b(b) {} 
    void foo() 
    { 
     m_b(*this); 
    } 
private: 
    B m_b; 
}; 

class B 
{ 
public: 
    template<class C> 
    void operator()(const C& c) 
    { 
     std::cout << "Bar!\n"; 
    } 
}; 


int main() 
{ 
    B b;   
    A<B> a(b); 
    a.foo(); 

    return 0; 
} 

Тогда я решил использовать указатель на функцию вместо функции объекта Ь, то есть я хотел сделать что-то вроде этого:

#include <iostream> 

template<class B> 
class A 
{ 
public: 
    A<B>(const B& b) : m_b(b) {} 
    void foo() 
    { 
     m_b(*this); 
    } 
private: 
    B m_b; 
}; 

template<class C> 
void bar(const C& c) 
{ 
std::cout << "Bar!\n"; 
} 

int main() 
{ 
    typedef void (*barPointer)(const A<barPointer>& a); // <--  
    A<barPointer> a(&bar); 
    a.foo(); 

    return 0; 
} 

Это, очевидно, не компилируется (обратите внимание на цикличность в < -). Мой вопрос: как бы это сделать?

+0

Простейшим решением является возврат к функциональному объекту; это также может иметь преимущества в производительности, поскольку он намного проще встраивать. У вас есть конкретная причина для поиска указателя функции? –

+0

Как объекты функции проще встраивать? Функция легко встроена, если ее тело видно. Это справедливо для функции-члена, а также для свободной функции. – wilhelmtell

+0

@wilhelmtell: функция-член указывается во время компиляции аргументом шаблона, поэтому его можно легко встраивать. Цель указателя функции указана во время выполнения аргументом конструктора; компилятор, возможно, не сможет сказать, что это такое, и может не включать его, даже если это возможно. –

ответ

0

Я думаю, что ключевой вопрос задать - это ваш barPointer тип? Это указатель на функцию, но по мере того, как вы пытались ее определить, вы создали бесконечно рекурсивное определение. Чтобы завершить рекурсию, вы должны рассмотреть, что такое «корень» или «базовый регистр» этого типа указателя. Поскольку вы знаете тип для экземпляра A, вы перейдете к своей функции, тогда вы действительно ищете тип «заполнителя», который позволит создать экземпляр шаблона без округлости. Это может быть очень «общий» тип функции-указателя, такой как void(*)(void*), или это может быть что-то более конкретное, но в любом случае я считаю, что это должен быть тип указателя функции, который не включает определение A, но может быть в качестве аргумента прошел экземпляр A<>. Наиболее общей формой будет void(*)(void*), но вы всегда можете определить некоторый тип полиморфного базового класса, а также для большей безопасности типов.

Вот, например, был бы пример наиболее общий случай:

typedef void (*generic_t)(void*); 

template<typename T> 
struct A 
{ 
     A(const T& t): func_ptr(t) {} 
     void foo() { func_ptr(this); } 
     T func_ptr; 
}; 

void func(void* arg) 
{ 
     const A<generic_t>* a = reinterpret_cast<const A<generic_t>*>(arg); 
} 

int main() 
{ 
     A<generic_t> a(&func); 
     a.foo(); 
     return 0; 
} 

Хотя это выглядит опасным, это не совсем, если учесть тот факт, что в вашем basePointer примере вы уже знали, тип объект, который вы собираетесь передать вашему указателю функции basePointer. Если вы хотите больше безопасности типа, чтобы предотвратить непреднамеренные ошибки, вы всегда можете создать некоторый тип абстрактного базового класса, который наследует A. Я говорю «абстрактный базовый класс», потому что это позволит вам использовать указатель, переданный функции без явного приведения к его производному типу. Тогда ваш тип «generic placeholder» -ptr типа может быть чем-то вроде void(*)(const Base&), а не небезопасным void(*)(void*).

Смежные вопросы