Warum kann die Funktionsvorlage nicht teilweise spezialisiert werden?

84

Ich weiß, dass die Sprachspezifikation eine teilweise Spezialisierung der Funktionsvorlage verbietet .

Ich würde gerne wissen, warum es das verbietet. Sind sie nicht nützlich?

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!
Nawaz
quelle
Denn template<typename T, typename U> void f(T t, U u) {}auch template<> void f(int t, char u) {}erlaubt.
Bindestrich
10
Ich finde es interessant, dass die Leute weiterhin Problemumgehungen anbieten, wenn die Frage nicht "Wie kann ich ein ähnliches Ziel erreichen" lautet, sondern "Was ist der Grund für dieses Verhalten?" ... Ich selbst kenne den Grund für diese Wahl nicht, aber ich gehe davon aus, dass Das Komitee muss einen Grund gehabt haben, die teilweise Spezialisierung von Funktionsvorlagen zu verbieten. Bisher ist die "engste" Erklärung der von Georgy gepostete Link, der nur auf die potenziellen "Risiken" einer teilweisen Spezialisierung von Funktionsvorlagen hinweist, wenn Überlastungen vorliegen. Ich glaube jedoch nicht, dass dies ein Grund ist, diese Funktion zu verbieten, daher
gehe

Antworten:

59

AFAIK, das in C ++ 0x geändert wurde.

Ich denke, es war nur ein Versehen (wenn man bedenkt, dass man den partiellen Spezialisierungseffekt immer mit ausführlicherem Code erzielen kann, indem man die Funktion als staticMitglied einer Klasse platziert).

Sie können den entsprechenden DR (Fehlerbericht) nachschlagen, falls vorhanden.

EDIT : Wenn ich das überprüfe, finde ich, dass andere das auch geglaubt haben, aber niemand kann eine solche Unterstützung im Standardentwurf finden. Dieser SO-Thread scheint darauf hinzudeuten, dass eine teilweise Spezialisierung von Funktionsvorlagen in C ++ 0x nicht unterstützt wird .

EDIT 2 : nur ein Beispiel dafür, was ich unter "Platzieren der Funktion als staticMitglied einer Klasse" verstanden habe:

#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
}
Prost und hth. - Alf
quelle
Haben Sie den Standard in n3225? Ich habe eine schnelle Suche durchgeführt, konnte sie aber nicht finden: /
Matthieu M.
1
ah sorry ... ein Wort fehlte. Ich habe das Dokument, konnte aber den jeweiligen Absatz nicht finden . Obwohl Ihre Bearbeitung gegeben ist, denke ich, ist es einfach, weil es nicht da drin ist :)
Matthieu M.
3
Dies wird in C ++ 0x nicht geändert. Ich bezweifle auch seine Nützlichkeit. Sie können jederzeit die Verwendung von partieller Vorlage und machen Überlastung Ordnung .
Johannes Schaub - litb
1
Spätes Update: hat sich acht Jahre später auch in C ++ 17 nicht geändert und scheint auch nicht in C ++ 20 einzutreten. Kann aber keinen Grund dafür sehen ...
Aconcagua
Dies ist bei weitem die umfassendste Umsetzung des Konzepts, glaube ich
Victor
18

Nun, Sie können wirklich keine Teilfunktions- / Methodenspezialisierung durchführen, aber Sie können eine Überladung durchführen.

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){...} 

Es ist der Weg, aber ich weiß nicht, ob es dich zufriedenstellt.

Michal W.
quelle
1
Wow, meine Gedanken waren voller Vorlagen, so dass ich wirklich vergaß, wie einfach die Dinge sein könnten :)
Johannes
1
Leider ist es nicht der Fall, wenn Sie verschiedene Argumente übergeben möchten, nachdem Sie die Funktion teilweise spezialisiert haben .. :(
Gwangmu Lee
Ich bin mir nicht sicher, was mit dem Übergeben verschiedener Vorlagen gemeint war, daher würde ich gerne wissen, wie es sich von einer teilweisen Spezialisierung unterscheidet. Könnten Sie bitte weitere Details angeben?
beginnt am
Was ist, wenn Sie nur zwei Funktionen für alle Integral- und Float-Typen wünschen?
Dmitriy Dokshin
14

Im Allgemeinen wird aufgrund von Problemen mit der Überlastung nicht empfohlen, Funktionsvorlagen überhaupt zu spezialisieren. Hier ist ein guter Artikel aus dem C / C ++ Users Journal: http://www.gotw.ca/publications/mill17.htm

Und es enthält eine ehrliche Antwort auf Ihre Frage:

Zum einen kann man sie nicht teilweise spezialisieren - so ziemlich nur, weil die Sprache sagt, dass man es nicht kann.

Georgy Pashkov
quelle
3
Der Artikel handelt nicht von einer teilweisen Spezialisierung, außer dass er einmal erwähnt wird.
Euri Pinhollow
11

Da Sie Klassen teilweise spezialisieren können, können Sie einen Funktor verwenden:

#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 ;
}
Kay F. Jahnke
quelle
1
Sie können dann eine einzelne Funktionsvorlage verwenden, um die Aufrufe zu tätigen und die hässliche ()()Syntax loszuwerden .
tmr232