2013-12-21 2 views
3

Привет, Я пытаюсь написать класс делегата, который может принимать аргумент шаблона, аналогичный стандартной сигнатуре функции, и создать делегат для указателя функции-члена, как показано ниже в основном. Код может быть упрощен, но это то, что я искал, было простым и быстрым решением этой проблемы с минимальными накладными расходами. Я думаю, что эта реализация очень близка к достижению того, что я хочу, могу ли я получить тип Т в классе без выполнения полиморфизма и т.д.std :: function like delegate template class

template<class T> 
struct FastDelegate {}; 

template<class R, class... Args> 
struct FastDelegate<R (Args...)> 
{ 
    template <typename T> 
    FastDelegate(T* t, R (T::*f)(Args...)) : m_t(t), m_f(f) {} 

    R operator()(Args... p) 
    { 
     return (m_t->*m_f)(std::forward<Args>(p)...); 
    } 

    T* m_t; // How can I capture T as a type in this partial specialization? 
    R (T::*m_f)(Args...); 
}; 

struct Test 
{ 
int add (int x, int y) { return x+y; } 
}; 

int main() 
{ 
int x = 5; 
int y = 4; 

Tester t; 
FastDelegate<int (int,int)> d (&t, &Test::calc); 
int z = d(x,y); 
} 
+0

Er, вся точка делегата, чтобы удалить тип во время компиляции, так что вы не можете получить доступ к типу, если вы стер ... – Mehrdad

+0

Кроме того, я думаю, что на «виртуальное наследование «вы, вероятно, имели в виду« полиморфизм времени выполнения », поскольку виртуальное наследование фактически не имеет к этому никакого отношения. – Mehrdad

+0

да, это то, что я имел в виду. Исправлено – bjackfly

ответ

4

Вы можете захватить объекты как void*, сохранить функцию-член в случайном типе функции члена и иметь функцию восстановления необходимых типов. Такой подход не позволяет выделять любую память в куче. Проблематичным шагом является преобразование из функции-члена какого-либо типа в другую функцию-член. Однако в соответствии с пунктом 5.2.10 [expr.reinterpret.cast] этот подход можно использовать безопасно, так как до тех пор, пока функция-член не возвращается к его первоначальному типу до использования:

[...] результат этого преобразования не определен, за исключением следующих случаев:

  • преобразование prvalue типа «указатель на функцию-член» на другой указатель на член типа функции и обратно к своему первоначальному типу дает исходный указатель значение члена.

Ниже приведен пример, который реализует этот подход. Обратите внимание, однако, что, вероятно, проще использовать std::function<R(Args...)> с подходящей лямбдой, поскольку стандартная библиотека, скорее всего, реализует такой подход, как в первую очередь.

#include <iostream> 
#include <utility> 

template<class T> 
struct FastDelegate {}; 

template<class R, class... Args> 
struct FastDelegate<R (Args...)> 
{ 
    struct dummy {}; 
    template <typename T> 
    FastDelegate(T* t, R (T::*f)(Args...)) 
     : m_t(t) 
     , m_f(reinterpret_cast<void (dummy::*)()>(f)) 
     , m_call([](void(dummy::*d)(), void* v, Args... a){ 
       typedef R (T::*mem)(Args...); 
       T* t = static_cast<T*>(v); 
       mem f = reinterpret_cast<mem>(d); 
       return (t->*f)(std::forward<Args>(a)...); 
      }) { 
    } 

    R operator()(Args... p) { 
     return (this->m_call)(this->m_f, this->m_t, std::forward<Args>(p)...); 
    } 

    void* m_t; 
    void (dummy::*m_f)(); 
    R  (*m_call)(void (dummy::*)(), void*, Args...); 
}; 

struct Tester 
{ 
int add (int x, int y) { 
    std::cout << "add(" << x << ", " << y << ")\n"; 
    return x+y; 
} 
}; 

int main() 
{ 
int x = 5; 
int y = 4; 

Tester t; 
FastDelegate<int (int,int)> d (&t, &Tester::add); 
int z = d(x,y); 
} 
+0

Удивительный! Никогда не знаешь, что ты можешь играть в лямбду вот так! –

+0

Это выглядит отлично, я буду принимать это как решение. Быстрое рассмотрение вопроса, является ли этот класс назначаемым или безопасно скопированным? – bjackfly

+0

@bjackfly: класс не хранит ничего интересного: всего пару указателей. Нет ничего, что делает класс не копируемым. Он не копирует объект, хотя (может быть, тоже, конечно). –

3

Вам не нужно захватывать типа T, потому что вы можете использовать в качестве t->*m_ffunction<R(Args...)>

template<class R, class... Args> 
struct FastDelegate<R (Args...)> 
{ 
    template <typename T> 
    FastDelegate(T* t, R (T::*f)(Args...)) 
     : m_f([=](Args... v){ return (t->*f)(std::forward(v)...); }) {} 

    R operator()(Args... p) 
    { 
     return m_f(std::forward<Args>(p)...); 
    } 

    std::function<R(Args...)> m_f; 
}; 

Если вы хотите сравнить 2 экземпляра FastDelegate путем сравнения t и f, до сих пор нет необходимости для типа информации, просто взять сырой указатель.

+0

Другими словами, то, что он спрашивает, невозможно. Вы просто скрыли полиморфизм под 'std :: function'. Это прекрасно, если не упомянуть, что он явно противоречит тому, что он искал. – Mehrdad

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