43
// 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;

    }
};

テンプレートの特殊化を記述し、char型専用にクラス全体のdefを個別に実行する方法を知っています。

しかし、1つのコードブロックですべてを処理したい場合はどうなりますか?

Tがintかcharかを確認するにはどうすればよいですか?

4

6 に答える 6

48

あなたが使用することができますtypeid

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

std::is_sameまたは、タイプ特性を使用できます。

if (std::is_same<T, int>::value)
于 2013-03-04T10:55:20.990 に答える
20

必要なのは、おそらくコンパイル時のようなものです。残念ながら、C++11はそのような言語構造をネイティブでサポートしていません。

ただし、2つのタイプが同一であるかどうかを確認したいだけの場合は、std::is_same<>タイプ特性が役立ちます。

#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;
    }
};

ただし、の値はコンパイル時にわかっていても、条件は実行時に評価されることに注意してください。is_same<T, int>::valueこれは、ステートメントのとブランチの両方をコンパイルする必要があることを意味します!truefalseif

たとえば、次のことは合法ではありません。

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!
}

また、Xeoがコメントで正しく指摘しているように、条件は常にtrueまたはに評価されるため、コンパイラーは警告を発行する可能性がfalseあります。そのため、2つのブランチの1つに到達不能コードが含まれます。

于 2013-03-04T10:55:34.923 に答える
8

単純なオーバーロードはどうですか?

// 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;
}

(標準では、 a の数値のアルファベット順は保証されていないことに注意してくださいchar。)

次に、それを単にincreaseasで呼び出しますreturn do_increase(element);

于 2013-03-04T10:56:37.400 に答える
5

ここでの通常の解決策は、追加の引数を使用してオーバーロードされた関数に転送することです。何かのようなもの:

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 );
    }
};

少し想像力を働かせれば、あらゆる種類の違いを思いつくことができます。追加の引数テンプレートを使用してターゲット関数を作成する場合は、SFINAE を活用することもできます。つまり、テンプレートの型置換が失敗するように仮引数を設計し、関数がオーバーロード セットで考慮されないようにします。また、すべての関数がインラインであるため、最適化すれば、余分なオーバーヘッドは発生しない可能性があります。

于 2013-03-04T10:58:43.073 に答える
0

これは Andy Prowls の回答に沿ったものですが、特殊化された最小限のヘルパー クラスを使用してコンパイル時にすべて行われます。

この例では、実際に特殊化を行うヘルパーがありますが、ヘルパー クラスに bool を取り、std::is_same<T, int>::valueその値をテンプレート パラメーターとして渡すようなものを使用することもできます。

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);
    }
};

これにより、クラス全体ではなく、単一の関数のみを特殊化できます。関数テンプレートの部分的な特殊化による VS2012 の制限に慣れているため、静的なテンプレート クラスを使用しています。

于 2013-03-05T20:09:48.057 に答える