テンプレートパラメータのタイプを確認するにはどうすればよいですか?


95

テンプレート関数と2つのクラスがあるとします

class animal {
}
class person {
}

template<class T>
void foo() {
  if (T is animal) {
    kill();
  }
}

Tが動物かどうかの確認方法を教えてください。実行時にチェックするものは必要ありません。ありがとう


58
「キル」の代わりに「ペット」を入れます:-)
JimBamFeng

回答:


132

使用is_same

#include <type_traits>

template <typename T>
void foo()
{
    if (std::is_same<T, animal>::value) { /* ... */ }  // optimizable...
}

通常、それは完全に機能しないデザインですが、あなたは本当に専門にしたいです

template <typename T> void foo() { /* generic implementation  */ }

template <> void foo<animal>()   { /* specific for T = animal */ }

また、明示的な(推論されていない)引数を持つ関数テンプレートを使用することは珍しいことにも注意してください。それは前例のないことではありませんが、多くの場合、より良いアプローチがあります。


2
Tありがとう!実際、彼らは
たくさん

3
@WhatABeautifulWorld:常にコードを因数分解して、型に依存する部分を特殊化可能な関数に
任せる

1
std :: is_sameを使用すると、他のテンプレートパラメータのコードが遅くなることはありませんか?
WhatABeautifulWorld

1
@WhatABeautifulWorld:特性値はすべて静的に知られています。コンパイラーが半分以上あれば、実行時のコストは発生しません。疑問がある場合は、アセンブリを確認してください。
Kerrek SB、2012

2
@ AdriC.S .: Tは推定されないため、実行できることはあまりありません。プライマリテンプレートを未実装のままにして特殊化を作成するか、で静的アサーションを追加できますis_same
Kerrek SB 2014

35

今日は、C ++ 17でのみ使用する方が良いと思います。

#include <type_traits>

template <typename T>
void foo() {
    if constexpr (std::is_same_v<T, animal>) {
        // use type specific operations... 
    } 
}

なしのif式本体でタイプ固有の操作を使用するとconstexpr、このコードはコンパイルされません。


8
代わりに、std::is_same<T, U>::valueより短いものを使用することができます:std::is_same_v<T, U>
Fureeish

9

C ++ 17では、バリアントを使用できます

を使用std::variantするには、ヘッダーを含める必要があります。

#include <variant>

その後、次のstd::variantようにコードを追加できます。

using Type = std::variant<Animal, Person>;

template <class T>
void foo(Type type) {
    if (std::is_same_v<type, Animal>) {
        // Do stuff...
    } else {
        // Do stuff...
    }
}

8
TとTypeはどのように関連付けられていますか?
マブラハム

4
この答えはいくつかの点で問題があります。実際のエラー(typeタイプの値Typeまたはここでis_same_vは意味をなさないテンプレート)に加えて、のコンテキストでは意味がありませんvariant。対応する「特性」はholds_alternativeです。
Pixelchemist

std::variantここではまったく不要です
tjysdsg

7

次のように、パラメータに渡される内容に基づいてテンプレートを特化できます。

template <> void foo<animal> {

}

これは、として渡されるタイプに基づいて、まったく新しい関数を作成することに注意してくださいT。これは、混乱を減らすため、通常は望ましい方法であり、基本的にはそもそもテンプレートを用意している理由です。


うーん。この方法は本当にテンプレート引数を特化するための唯一の望ましい方法ですか?テンプレート関数内で管理する必要がある10の異なる子クラスがあるとします。各クラスに10の異なるテンプレート関数を実際に記述する必要がありますか?私はここで核心を逃しているかもしれないと思う。
VolkanGüven2017

type_traitsを使いたくない人にとっては、これは本当に良い考えのように思えます。誰かが述べたように、メインロジックは別の関数で実行でき、型を示す追加のフラグを受け入れます。この特殊な宣言は、フラグをそれに応じて設定し、他のすべての引数に何も触れずに直接渡すことができます。したがって、10の異なるクラスを処理する必要がある場合、基本的には10の異なる関数定義に対して10行です。しかし、複数のテンプレート変数がある場合、これは非常に複雑になります。
Harish Ganesan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.