5

Ho il seguente codice di base:Funzione prendendo sia puntatore a membro-funzione e puntatore a const membro funzione

template <typename Type> 
class SomeClass { 
public: 
    template <typename ReturnType, typename... Params> 
    void register_function(const std::pair<std::string, ReturnType (Type::*)(Params...)> fct) { 
     auto f = [fct](Params... params) -> ReturnType { return (Type().*fct.second)(std::ref(params)...); } 
     // ... 
    } 
}; 

Questo funziona quando passo un puntatore ad un organo-funzione (non-const). Tuttavia, se voglio passare un puntatore a un membro funzione const, il risultato e 'un errore di compilazione e devo duplicare la funzione di cui sopra per ottenere questo codice:

template <typename Type> 
class SomeClass { 
public: 
    template <typename ReturnType, typename... Params> 
    void register_function(const std::pair<std::string, ReturnType (Type::*)(Params...)> fct) { 
     auto f = [fct](Params... params) -> ReturnType { return (Type().*fct.second)(std::ref(params)...); } 
     // ... 
    } 

    template <typename ReturnType, typename... Params> 
    void register_function(const std::pair<std::string, ReturnType (Type::*)(Params...) const> fct) { 
     auto f = [fct](Params... params) -> ReturnType { return (Type().*fct.second)(std::ref(params)...); } 
     // ... 
    } 
}; 

Ora, posso passare sia const- funzioni membro e funzioni membro non const. Ma, ora, il codice è duplicato e la manutenibilità è ridotta.

C'è un modo per unire queste due funzioni in una funzione tenendo entrambe le funzioni const-member e non-const-member?

Nota importante: Devo davvero utilizzare una funzione puntatore come parametro (nessuna funzione std ::).

Modifica: ho aggiunto un po 'di codice in più. All'interno delle funzioni, costruisco una chiusura che corrisponde alla firma della funzione membro (stessi tipi di ritorno e parametri). Tale chiusura verrà memorizzato e utilizzato in seguito per la realizzazione di riflessione (more here)

+0

Perché non semplicemente 'template register_function void (Fun FCT)'? – fredoverflow

+0

Ho aggiornato la mia domanda con un po 'di codice in più. All'interno di lambdas, potrei chiamare std :: bind o usare direttamente il puntatore di funzione membro su una nuova istanza di oggetto. Questo è il motivo per cui ho davvero bisogno di accedere a ReturnType e ai nomi dei tipi Params. –

+0

È tutta la tua base di codice? lol davvero –

risposta

5

si potrebbe scrivere un tipo di tratto, sulla base del quale vi dirà se alcuni MF è una funzione puntatore-a-membro sulla Type:

template <typename C, typename T> 
struct is_pointer_to_member_helper : std::false_type { }; 

template <typename C, typename T> 
struct is_pointer_to_member_helper<C, T C::*> : std::is_function<T> { }; 

template <typename C, typename T> 
struct is_pointer_to_member : is_pointer_to_member_helper<C, 
            std::remove_cv_t<T> 
           > { }; 

e utilizzarlo per garantire che si ottiene solo uno di questi:

template <typename Type> 
class SomeClass { 
public: 
    template <typename MF> 
    std::enable_if_t<is_pointer_to_member<Type, MF>::value> 
    register_function(const std::pair<std::string, MF> fct) 
    { 
     auto f = [fct](auto&&... params) { 
      return (Type{}.*fct.second)(std::forward<decltype(params)>(params)...); 
     }; 

     // ... 
    } 
}; 
+0

Abbiamo 'std :: is_member_function_pointer' –

+0

@ T.C. Non lo sapevo. Immagino ancora voglia di controllare esplicitamente quale classe è un puntatore a funzione membro di. – Barry

+0

Risposta interessante. Tuttavia, ho bisogno di accedere al ReturnType e al Params ... typenames. Ho aggiornato la mia domanda con un po 'di codice in più: utilizzo lambdas nel mio codice in cui posso chiamare std :: bind o utilizzare direttamente il puntatore della funzione su una nuova istanza Type. –

Problemi correlati