wake-up-neo.com

wie mache ich einen if else abhängigen Typ in C++ - Vorlage?

// template specialization
#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
    T element;
  public:
    mycontainer (T arg) {element=arg;}
    T increase () {

    //if(T.type==int)//how to do this or something similar?
    //do this if an int
    return ++element;

    //if(T.type==char)
     //if ((element>='a')&&(element<='z'))
      //element+='A'-'a';
      //return element;

    }
};

Ich kann eine Schablonenspezialisierung schreiben und eine separate ganze Klasse def nur für den Typ char ausführen.

Was aber, wenn ich alles in nur einem Codeblock behandeln wollte?

Wie kann ich überprüfen, ob T ein Int oder ein Char ist?

28
user494461

Sie könnten typeid verwenden:

if (typeid(T) == typeid(int))

Oder Sie können die std::is_same-Typ-Eigenschaft verwenden:

if (std::is_same<T, int>::value)
26

Was Sie wollen, ist wahrscheinlich so etwas wie eine compile-time, wenn . Leider unterstützt C++ 11 ein solches Sprachkonstrukt nicht nativ.

Wenn Sie jedoch nur prüfen möchten, ob zwei Typen identisch sind, sollte Ihnen das Merkmal std::is_same<> helfen:

#include <type_traits> // <== INCLUDE THIS STANDARD HEADER

// class template:
template <class T>
class mycontainer 
{
    T element;
public:
    mycontainer (T arg) {element=arg;}
    T increase () 
    {
        if (std::is_same<T, int>::value)   // <== THIS IS HOW YOU WOULD USE IT
            return ++element;

        if (std::is_same<T, char>::value)  // <== THIS IS HOW YOU WOULD USE IT
        {
            if ((element>='a') && (element<='z'))
                element+='A'-'a';
        }

        return element;
    }
};

Beachten Sie jedoch, dass die Bedingung zur Laufzeit ausgewertet wird, obwohl der Wert von is_same<T, int>::value zur Kompilierzeit bekannt ist. Dies bedeutet, dass beide die true und der false-Zweig der if-Anweisung kompilieren müssen!

Zum Beispiel wäre folgendes nicht legal:

if (std::is_same<T, int>::value)
{
    cout << element;
}
else if (std::is_same<T, my_class>::value)
{
    element->print();  // Would not compile when T is int!
}

Wie Xeo in den Kommentaren richtig angegeben wurde, gibt der Compiler wahrscheinlich Warnungen aus, da Ihre Bedingung immer in true oder in false ausgewertet wird, sodass einer der beiden Zweige nicht erreichbaren Code enthält.

13
Andy Prowl

Wie wäre es mit einer einfachen Überladung?

// in the private section
static int& do_increase(int& i){ return ++i; }
static char& do_increase(char& c){
  if(c >= 'a' && c <= 'z')
    c += 'A' - 'a';
  return c;
}
template<class U>
static U& do_increase(U& arg){
  // some default implementation?
  return arg;
}

(Beachten Sie, dass der Standard für die numerischen Werte einer char keine alphabetische Reihenfolge garantiert.)

Dann nennen Sie das einfach in increase als return do_increase(element);.

7
Xeo

Sie können explizite Vorlagenspezialisierung verwenden

#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
    T element;
  public:
    mycontainer (T arg) {element=arg;}
    T increase();
};


template<>
int mycontainer<int>::increase(){
    return ++element;
}

template<>
char mycontainer<char>::increase(){
    if ((element>='a')&&(element<='z'))
       element+='A'-'a';
    return element;
}

int main(){
        mycontainer<int> A(10);
        mycontainer<char> B('x');

        cout << A.increase() <<endl;
        cout << B.increase() <<endl;
        return 0;
}
7
xvan

Die übliche Lösung hier ist das Weiterleiten an eine überladene Funktion Mit einem zusätzlichen Argument. So etwas wie:

template <typename T>
class MyContainer
{
    T increase( int const* ) { /* special treatment for int */ }
    T increase( ... )        { /* default treatment         */ }
public:
    T increase()
    {
        return increase( (T const*)0 );
    }
};

Mit etwas Phantasie können Sie alle möglichen Unterschiede feststellen. Wenn Sie die Zielfunktionen mit den zusätzlichen -Argumentvorlagen erstellen, können Sie sogar das Dummy-Argument SFINAE: design Nutzen, sodass die Ersetzung des Vorlagentyps fehlschlägt und Die Funktion nicht in der Überladungsgruppe berücksichtigt wird . Und Da alle Funktionen inline sind, ist es wahrscheinlich, dass Kein zusätzlicher Aufwand anfällt, vorausgesetzt, Sie optimieren.

3
James Kanze

Dies entspricht der Antwort von Andy Prowls, wird jedoch zur Kompilierzeit mit einer minimalen Hilfsklasse mit Spezialisierung ausgeführt.

In diesem Fall haben Sie einen Helfer, der tatsächlich die Spezialisierung durchführt, aber Sie könnten auch die Helper-Klasse haben, die einen Bool nimmt und dann etwas wie std::is_same<T, int>::value verwendet, um diesen Wert als Vorlagenparameter zu übergeben.

template <typename T>
struct myContainerHelper;
{
    // General Case
    static inline T increase(T element)
    {
        return ++element;
    }
};

template <>
struct myContainerHelper<char>
{
    // Specific case
    static inline char increase(char element)
    {
        if ((element>='a')&&(element<='z')) element+='A'-'a';
        return element;
    }
};

template <class T>
class mycontainer 
{
    T element;
public:
    mycontainer (T arg) {element=arg;}
    T increase () 
    {
        return myContainerHelper<T>::increase(element);
    }
};

Dadurch können Sie nur die einzelne Funktion anstelle der gesamten Klasse spezialisieren. Ich verwende eine Vorlagenklasse mit Statik, da ich an VS2012-Einschränkungen mit teilweiser Spezialisierung für Funktionsvorlagen gewöhnt bin.

0
NtscCobalt