Fare sfinae funziona per funzioni con tipo di ritorno dedotto?

Considera il seguente codice:

// -------------------------------------------------------------------------- // // Preprocessor #include  #include  #include  #include  #include  // -------------------------------------------------------------------------- // // -------------------------------------------------------------------------- // // Calls a function without arguments if it can be called template < class F, class... Args, class = decltype(std::declval()()) > decltype(auto) apply(F&& f) { std::cout<<"apply(F&& f)"<<std::endl; return std::forward(f)(); } // Calls a function with arguments if it can be called template < class F, class Arg, class... Args, class = decltype(std::declval()( std::declval(), std::declval()... )) > decltype(auto) apply(F&& f, Arg&& arg, Args&&... args) { std::cout<<"apply(F&& f, Arg&& arg, Args&&... args)"<<std::endl; return std::forward(f)( std::forward(arg), std::forward(args)... ); } // Does nothing if the function cannot be called with the given arguments template  void apply(F&& f, Args&&... args) { std::cout<<"apply(F&& f, Args&&... args)"< decltype(std::forward(x).capacity()) { return std::forward(x).capacity(); }; auto g = [](auto&& x) -> decltype(auto) { return std::forward(x).capacity(); }; auto h = [](auto&& x) { return std::forward(x).capacity(); }; // Test apply(f, std::vector()); // -> sfinae works apply(g, std::vector()); // -> sfinae works apply(h, std::vector()); // -> sfinae works apply(f, std::array());// -> sfinae works //apply(g, std::array()); -> sfinae fails, does not compile //apply(h, std::array()); -> sfinae fails, does not compile // Return return 0; } // -------------------------------------------------------------------------- // 

L’utilità si apply , applica una funzione agli argomenti quando può essere compilata, altrimenti non fa nulla. Il meccanismo si basa su sfinae. Tuttavia, per la funzione il cui tipo di ritorno è dedotto dal corpo, come g e h nell’esempio precedente, sfinae non riesce. Ci sarebbe un modo intelligente in C ++ 14 di modificare l’utilità di apply modo che costringa la sfinae a calciare anche per le funzioni il cui tipo di ritorno è dedotto dal corpo?

Nota: mi piacerebbe fare g h lavorare come f , il che significa che la chiamata di apply dovrebbe chiamare la versione void .

SFINAE può solo rilevare errori di sostituzione.

Alcuni errori quando si chiama una funzione non possono essere errori di sostituzione. Questi includono errori che si verificano quando si analizza il corpo di una funzione.

C ++ ha scelto esplicitamente di escludere questi errori dall’triggerszione di SFINAE e invece di generare errori gravi per liberare i compilatori dal dover compilare corpi di funzioni arbitrarie per determinare se si verifica SFINAE. Poiché SFINAE deve essere eseguito durante la risoluzione di sovraccarico, questo semplifica il codice di risoluzione di sovraccarico di un compilatore C ++.

Se vuoi che il tuo codice sia amichevole con SFINAE, non puoi usare lambda come g o h .

Il tuo SFINAE funziona bene, per quanto riguarda la apply .

Per quanto riguarda il perché f funziona, è perché:

  1. È un modello e

  2. Fallisce già nella fase di sostituzione.

Ciò significa che ha SFINAE di se stesso, e per f il do-nothing predefinito è chiamato (per array ), come previsto.


Ci sarebbe un modo intelligente in C ++ 14 per modificare l’utilità apply in modo che costringa …

No, apply già fa tutto ciò che dovrebbe.

Riguardo al motivo per cui g() e h() non funzionano, produrranno errori gravi quando li chiamerai con qualcosa che non ha capacity . Una funzione di utilità che tu (prova a) applica dopo non può rimuovere quell’errore grave. L’unico modo per risolvere questo problema è il “doppio smacco” SFINAE, come fai tu in f()