Perché il modello di funzione non può essere parzialmente specializzato?


89

So che la specifica del linguaggio proibisce la specializzazione parziale del modello di funzione.

Vorrei conoscere la logica del perché lo vieta? Non sono utili?

template<typename T, typename U> void f() {}   //allowed!
template<> void f<int, char>()            {}   //allowed!
template<typename T> void f<char, T>()    {}   //not allowed!
template<typename T> void f<T, int>()     {}   //not allowed!

Per template<typename T, typename U> void f(T t, U u) {}anche template<> void f(int t, char u) {}è permesso.
dashesy

10
Trovo interessante che le persone continuino a fornire soluzioni alternative quando la domanda non è "come posso raggiungere un obiettivo simile" ma "qual è la logica alla base di questo comportamento" ... Io stesso non conosco il motivo di questa scelta, ma presumo comitato deve aver avuto un motivo per vietare la specializzazione parziale del modello di funzione. Finora la spiegazione "più vicina" è il link pubblicato da Georgy, che indica solo i potenziali "rischi" della specializzazione parziale del modello di funzione quando sono presenti sovraccarichi. Tuttavia, non credo che sia un motivo per vietare questa funzione, quindi presumo che ci sia di più in questo ..
bartgol

Risposte:


59

AFAIK che è cambiato in C ++ 0x.

Immagino sia stata solo una svista (considerando che puoi sempre ottenere l'effetto di specializzazione parziale con codice più dettagliato, posizionando la funzione come staticmembro di una classe).

Potresti cercare il DR (Rapporto sui difetti) pertinente, se presente.

EDIT : controllando questo, trovo che anche altri lo abbiano creduto, ma nessuno è in grado di trovare un tale supporto nella bozza di standard. Questo thread SO sembra indicare che la specializzazione parziale dei modelli di funzione non è supportata in C ++ 0x .

EDIT 2 : solo un esempio di cosa intendevo con "posizionare la funzione come staticmembro di una classe":

#include <iostream>
using namespace std;

// template<typename T, typename U> void f() {}   //allowed!
// template<> void f<int, char>()            {}   //allowed!
// template<typename T> void f<char, T>()    {}   //not allowed!
// template<typename T> void f<T, int>()     {}   //not allowed!

void say( char const s[] ) { std::cout << s << std::endl; }

namespace detail {
    template< class T, class U >
    struct F {
        static void impl() { say( "1. primary template" ); }
    };

    template<>
    struct F<int, char> {
        static void impl() { say( "2. <int, char> explicit specialization" ); }
    };

    template< class T >
    struct F< char, T > {
        static void impl() { say( "3. <char, T> partial specialization" ); }
    };

    template< class T >
    struct F< T, int > {
        static void impl() { say( "4. <T, int> partial specialization" ); }
    };
}  // namespace detail

template< class T, class U >
void f() { detail::F<T, U>::impl(); }    

int main() {
    f<char const*, double>();       // 1
    f<int, char>();                 // 2
    f<char, double>();              // 3
    f<double, int>();               // 4
}

hai lo standard in n3225? Ho fatto una ricerca veloce ma non sono riuscito a trovarlo: /
Matthieu M.

1
ah scusa ... mancava una parola. Ho il documento, ma non sono riuscito a trovare il paragrafo in particolare . Anche se vista la tua modifica, immagino sia semplicemente perché non è lì :)
Matthieu M.

3
Questo non è cambiato in C ++ 0x. Dubito anche della sua utilità. È sempre possibile sovraccaricare il modello e utilizzare l' ordinamento parziale .
Johannes Schaub - litb

1
Aggiornamento tardivo: non è cambiato nemmeno in C ++ 17 otto anni dopo e non sembra nemmeno entrare in C ++ 20. Non riesco a vedere alcun motivo, però ...
Aconcagua

Questa è di gran lunga l'implementazione più completa del concetto, credo
Victor

19

Bene, non puoi davvero fare la specializzazione parziale di funzione / metodo, tuttavia puoi eseguire il sovraccarico.

template <typename T, typename U>
T fun(U pObj){...}

// acts like partial specialization <T, int> AFAIK 
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...} 

È così ma non so se ti soddisfa.


2
Wow, la mia mente era piena di modelli tali che ho davvero dimenticato quanto potessero essere semplici le cose :)
Johannes

2
Sfortunatamente non è il caso quando vuoi passare argomenti variadici dopo aver parzialmente specializzato la funzione .. :(
Gwangmu Lee

Non sono sicuro di cosa significhi passare modelli variadici, quindi mi piacerebbe sapere in che modo è diverso da una specializzazione parziale. Potresti fornire maggiori dettagli?
beginpluses

E se si volessero solo due funzioni per tutti i tipi interi e float?
Dmitriy Dokshin

15

In generale, non è consigliabile specializzare i modelli di funzione, a causa di problemi con il sovraccarico. Ecco un buon articolo dal C / C ++ Users Journal: http://www.gotw.ca/publications/mill17.htm

E contiene una risposta onesta alla tua domanda:

Per prima cosa, non puoi specializzarli parzialmente, praticamente solo perché la lingua dice che non puoi.


3
L'articolo non riguarda la specializzazione parziale oltre al fatto che viene menzionato una volta.
Euri Pinhollow

11

Poiché puoi specializzare parzialmente le classi, puoi usare un funtore:

#include <iostream>

template < typename dtype , int k > struct fun
{
 int operator()()
 {
  return k ;
 }
} ;

template < typename dtype > struct fun < dtype , 0 >
{
 int operator()()
 {
  return 42 ;
 }
} ;

int main ( int argc , char * argv[] )
{
 std::cout << fun<float,5>()() << std::endl ;
 std::cout << fun<float,0>()() << std::endl ;
}

1
È quindi possibile utilizzare un unico modello di funzione per effettuare le chiamate, eliminando la brutta ()()sintassi.
tmr232
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.