2015-01-27 6 views
5

Kurzfassung: Ich habe eine Template-Funktion, die "universal" ist, aber ich möchte den Benutzer zwingen, den Typ des Arguments explizit anzugeben, sie übergeben als Parameter an diese Funktion.Gibt es eine Möglichkeit, den Benutzer zu zwingen, den Template-Argumenttyp explizit anzugeben?

Irgendwelche Ideen?

Lange Version: klingt wie ein schreckliches Design, aber hier ist mein Fall und ich kann mir im Moment nichts besseres vorstellen.

Ich versuche ::setsockopt in einer kleinen socket Klasse "zu implementieren" (und ich möchte nicht Tonnen von Funktionen, verschiedene Argumente und das gleiche tun). Zum Beispiel:

template< typename OPTION_VALUE_TYPE > 
bool set_option(int level, int option_name, const OPTION_VALUE_TYPE& value) 
{ 
    return -1 != ::setsockopt(fd_, level, option_name, &value, sizeof(value)); 
} 

ABER, könnte dies auf die folgende Situation führen - set_option mit 1 Aufruf versucht unsigned char Option setzen würde zum Ausfall führen, wie 1int ist. Korrekte Verwendung wäre:

set_option< unsigned char >(level, option, 1); 

als

set_option(level, option, 1); 

kompiliert völlig in Ordnung, aber schrecklich falsch sein.

Antwort

4

Ja, Sie müssen nur den Template-Parameter in einer Weise verwenden, aus dem sie nicht von den Argumenten abgeleitet werden kann. Ein üblicher Weg, dies zu tun ist ein typedef in einer Template-Klasse mit:

template <typename T> 
struct identity { 
    typedef T type; 
}; 

template <typename OPTION_VALUE_TYPE> 
bool set_option(int level, int option_name, 
       typename identity<const OPTION_VALUE_TYPE&>::type value); 

Um einen Typ bereits in der Standardbibliothek verwenden, können Sie enable_if verwenden:

template <typename OPTION_VALUE_TYPE> 
bool set_option(int level, int option_name, 
       typename std::enable_if<true, const OPTION_VALUE_TYPE&>::type value); 

Der Grund dieser doesn‘ t-Typ Argument Abzug zulassen, weil der Compiler nicht Spezialisierungen von identity ausschließen kann: der Compiler kann nicht ausschließen Sie

template <> 
struct identity<U> { typedef V type; }; 

wh tun ere identity<U>::type wäre nicht mehr U.

+2

Andere Optionen aus der Standard-Bibliothek wäre 'typename add_const :: type &' oder 'typename add_lvalue_reference :: type', die wahrscheinlich ein bisschen klarer sind. Die Verwendung von 'enable_if' könnte die Leute dazu bringen zu glauben, dass einige SFINAE beteiligt sind. –

+2

@ JonathanWakely Das ist ein guter Punkt. Auf der anderen Seite macht die Verwendung von 'add_const' oder' add_lvalue_reference' nicht klar, dass etwas Spezielles vor sich geht, und könnte jemanden dazu bringen, eine Code-Bereinigung durchzuführen, indem er einfach 'const OPTION_VALUE_TYPE &' ausdrückt. Ich denke, dass es für beide etwas zu sagen gibt, und ich denke, der klarste Ansatz besteht darin, diese "Identitäts" -Hilfsklasse zu erstellen und einfach die Standard-Bibliothekstypen zu vergessen. – hvd

+0

Ja, guter Punkt. "Identität" dient keinem anderen Zweck als dem, also ist es die expressivste Lösung. –

4

den Vorlagentyp in einem nicht abgeleiteten Kontext wie in der folgenden Put:

template <typename T> struct identity { using type = T; }; 

template <typename OPTION_VALUE_TYPE> 
bool set_option(int level, 
       int option_name, 
       const typename identity<OPTION_VALUE_TYPE>::type& value); 
Verwandte Themen