Template-Spezialisierung mit std::is_same



  • Hi,

    ich stehe gerade ein wenig auf dem Schlauch. Ich habe ein Funktions-Template:

    template <typename InType, typename OutType>
    OutType MyFunction (const InType &Input)
    {
        // do something and return
    }
    

    Dieses würde ich gerne spezialisieren, falls InType und OutType identisch sind. Allerdings sind die Versuche std::enable_if und/oder std::is_same unterzubringen gescheitert (wahrscheinlich einfach nicht die richtige Stelle). Denn die Funktion würde gar nicht erst aufgerufen werden oder ich erhalte C2995 Fehlermeldungen.

    Bisher löste einzig eine if is_same Abfrage am Anfang der Funktion oder die explizite Spezialisierung auf sämtliche Datentypen das Problem (beides aber eher suboptimal).

    Kann mir bitte jemand ein wenig auf die Sprünge helfen?


  • Mod

    template <typename InType, typename OutType> 
    OutType MyFunction (const InType &Input) 
    { 
        if constexpr(std::is_same_v<InType, OutType>)
          // do somethin'
        else 
          // do somethin' else
    }
    


  • Generell kann man einige Dinge viel einfacher erledigen wenn man das Funktionstemplate nur verwendet um eine statische Funktion eines Klassentemplates aufzurufen.
    Also quasi

    template <typename InType, typename OutType>
    struct MyFunctionImpl
    {
         static OutType execute(const InType &Input)
         {
             ...
         }
    };
    
    template <typename Type>
    struct MyFunctionImpl<Type, Type>
    {
         static Type execute(const Type &Input)
         {
             ...
         }
    };
    
    template <typename InType, typename OutType>
    OutType MyFunction (const InType &Input)
    {
        return MyFunctionImpl<InType, OutType>::execute(Input);
    }
    

    Wobei ich mir hier jetzt nicht 100% sicher bin ob der Returnwert 1x unnötig kopiert wird. Ich würde sagen typischerweise nein, aber ... falls es wichtig ist am besten ausprobieren.

    Und: Wieso vertauscht du nicht die beiden Template-Parameter? Dann musst du InType im Normalfall nicht angeben...


  • Mod

    Der klassische C++03-kompatible Weg mit enable_if:

    template <typename T, typename U>
    struct is_same {
        static const bool value = false;
    };
    template <typename T>
    struct is_same<T, T> {
        static const bool value = true;
    };
    
    template <bool, typename>
    struct enable_if {
    };
    template <typename T>
    struct enable_if<true, T> {
        typedef T type;
    };
    
    template <typename OutType, typename InType>
    typename enable_if<is_same<OutType, InType>::value, OutType>::type foo(const InType& x)
    {
        // OutType == InType
        return x;
    }
    template <typename OutType, typename InType>
    typename enable_if<!is_same<OutType, InType>::value, OutType>::type foo(const InType& x)
    {
        // OutType != InType
        return x + x;
    }
    
    #include <iostream>
    int main()
    {
        std::cout << foo<int>(1) << '\n'
                  << foo<long>(1) << '\n';
    }
    

    compiler-explorer
    ideone



  • Vielen Dank an euch!

    hustbaers Variante macht wahrscheinlich ein paar Fälle in meinem SDK überschaubarer. Das werde ich mal umbauen und testen. Und ja, Reihenfolge der Template-Parameter kann ich noch ändern. War jetzt nur ein Minimalbeispiel, da hab ich nicht darauf geachtet ^^

    Haha, Camper - daran, dass enable_if dort hin zu packen, hab ich natürlich nicht gedacht -.-' Aber das passt am ehesten vom Stil her zum Rest vom Code.

    Ähnlich wie Arcoth hatte ich es vorher. Dass das allerdings mittlerweile auch als constexpr möglich ist, macht es wieder interessant. Ist doch am übersichtlichsten.


  • Mod

    Falls du es mit wirklich antiken Compilern zu tun hast, die enable_if nicht wie gezeigt unterstützen (und die zu testende Bedingung etwas komplizierter ist, so dass man sie nicht so wie is_same durch direkte Spezialisierung erschlagen bekommt), bleibt noch die Möglichkeit, das Ganze durch Tag-Dispatching zu lösen. In irgendeiner Form muss das jeder Compiler unterstützen, weil es des Öfteren in der Standardbibliothek benötigt wird.



  • Arcoth schrieb:

    if constexpr(std::is_same_v<InType, OutType>)
    

    Auch wenn die Lösung echt schön ist und du bei der Sprachevolution immer ganz vorne mit dabei bist, wäre es entgegenkommend, auf den Sprachstandard hinzuweisen, der dafür erforderlich ist.
    Ist C++17 überhaupt schon durch die komplette Pipeline? Falls ja, will ich nix gesagt haben und das nochmal durchgehen lassen - ansonsten siehst du sicher auch ein dass man das besser noch etwas qualifizieren sollte 😉



  • Du bist disqualifiziert.


Anmelden zum Antworten