2013-02-19 11 views
7
#include <functional> 

void f1(int) 
{} 

void f2(int, ...) 
{} 

int main() 
{ 
    std::function<void(int)>  g1 = f1; // OK. 
    std::function<void(int, ...)> g2 = f2; // Error! Not standard C++! 
} 

Perché C++ 11 non forniscono una classe template specializzata come segue:Perché C++ 11 non supporta 'std :: function <void (int, ...)>'?

template<class ResultType, class... ArgTypes> 
class function<ResultType(ArgTypes......)> 
{ 
    // ... ... ... 
}; 
+0

Hai testato un modello simile a quello per vedere se avrebbe funzionato? – Omnifarious

+1

Entrambi i frammenti mostrano cose completamente diverse. I modelli Variadic sono gestiti in fase di compilazione. Gli argomenti della variabile di stile "C" vengono gestiti in fase di runtime. – mfontanini

+0

La sintassi dei parametri '...' (non nel modello variadic) viene mantenuta per compatibilità con le versioni precedenti con C. Il suo utilizzo è altamente sconsigliato. –

risposta

5

non intendo fornire la ragione ultima per cui che la specializzazione non è fornito (non so che), ma forse potrei suggerire alcuni degli ostacoli tecnici che si potrebbero incontrare nel tentativo di implementarlo. Spero che questo ti dia la sensazione del perché la specializzazione non è lì.

Consideriamo dapprima come è possibile implementare il modello di classe std::function<>. La tecnica di cancellazione del tipo che sta alla base il suo design potrebbe essere abbozzato come segue (questo è solo un illustrativo semplificazione, l'attuazione reale è molto più complessa):

#include <memory> 

template<typename T> 
struct function { }; 

template<typename R, typename... Args> 
struct function<R(Args...)> 
{ 

public: 

    template<typename F> 
    function(F&& f) : _holder(
     new holder<typename std::decay<F>::type>(std::forward<F>(f)) 
     ) 
    { } 

    R operator() (Args&&... args) 
    { _holder->call(std::forward<Args>(args)...); } 

private: 

    struct holder_base 
    { virtual R call(Args&&... args) = 0; }; 

    template<typename F> 
    struct holder : holder_base 
    { 
     holder(F&& f) : _f(std::forward<F>(f)) { } 
     R call(Args&&... args) { return _f(std::forward<Args>(args)...); } 
     F _f; 
    }; 

    std::unique_ptr<holder_base> _holder; 
}; 

Ora vediamo come la specializzazione per ellissi sarebbe simile . Prima di tutto, il numero e il tipo degli argomenti forniti a una funzione variadica è non corretti nella firma di quella funzione. Pertanto, l'operatore di call del nostro modello di specializzazione deve essere un modello di funzione di accettare qualsiasi numero e tipo di argomenti:

template<typename R, typename... Args> 
struct function<R(Args.......)> 
{ 
    ... 

    template<typename... Ts> 
    R operator() (Args&&... args, Ts&&... ts) 
    { _holder->call(std::forward<Args>(args)..., std::forward<Ts>(ts)...); } 

    ... 

Questo ci costringe, a sua volta, per fare holder<> s' operatore di call un modello Funzione Variadica. Tuttavia, per realizzare la cancellazione del tipo, lo stesso operatore di chiamata deve essere virtual ei modelli di funzione non possono essere virtual in C++.

Le cose sarebbero certamente più facili se argomenti variadici (sto parlando di ellissi qui) potrebbero essere facilmente inoltrati senza dover ricorrere a parametri di modelli variadic e inoltro perfetto. Tuttavia, non sono a conoscenza di un modo semplice per farlo, e soprattutto non se nessun altro argomento deve essere passato alla funzione rispetto a quelli corrispondenti alla lista variadica.

+0

Penso che ci siano altri approcci che potresti prendere. Ma sì, le difficoltà tecniche dell'attuazione mi fanno male alla testa, e non sono sicuro che si possa fare in modo pulito. – Omnifarious

+0

Si * potrebbe * provare a passare un oggetto 'va_args' al virtuale' operator() (Args ..., va_args vargs) ', e quindi provare ad espanderlo in qualche modo nell'operatore' holder''s() ' ...ma penso che sarebbe poderoso. – Xeo

Problemi correlati