Bir şablon parametresinin türü nasıl kontrol edilir?


97

Bir şablon işlevim ve iki sınıfım olduğunu varsayalım

class animal {
}
class person {
}

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

T'nin hayvan olup olmadığını nasıl kontrol ederim? Çalışma süresi boyunca kontrol eden bir şeye sahip olmak istemiyorum. Teşekkürler


62
"Kill" yerine "evcil hayvan"
koyardım

Yanıtlar:


135

Kullanım is_same:

#include <type_traits>

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

Genelde bu tamamen işe yaramaz bir tasarımdır ve gerçekten uzmanlaşmak istersiniz :

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

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

Ayrıca, açık (çıkarılmamış) bağımsız değişkenlere sahip işlev şablonlarına sahip olmanın olağandışı olduğunu unutmayın. Duyulmamış bir şey değil, ama çoğu zaman daha iyi yaklaşımlar var.


2
T Teşekkürler! Aslında bir sürü kodu paylaşıyorlar, bu yüzden onu gerçekten kopyalayamıyorum
WhatABeautifulWorld

3
@WhatABeautifulWorld: Tipe bağlı parçanın özelleştirilebilir bir işleve indirilebilmesi için kodunuzu her zaman çarpanlara ayırabilirsiniz ...
Kerrek SB

1
Hızlı bir takip, eğer std :: is_same kullanırsam, diğer şablon parametreleri için kodu yavaşlatmaz, değil mi?
WhatABeautifulWorld

1
@WhatABeautifulWorld: Özellik değerlerinin tümü statik olarak bilinir. Derleyicinizin yarı düzgün olması koşuluyla herhangi bir çalışma zamanı maliyeti olmamalıdır. Yine de şüpheniz varsa montajı kontrol edin.
Kerrek SB

2
@ AdriC.S .: Çıkarılmadığı Tiçin yapabileceğiniz pek bir şey yok. Birincil şablonu uygulanmadan bırakabilir ve bir uzmanlık oluşturabilir veya ile statik bir iddia ekleyebilirsiniz is_same.
Kerrek SB

38

Bence bugün kullanmak daha iyidir, ancak yalnızca C ++ 17 ile.

#include <type_traits>

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

İf ifade gövdesinde tipe özgü bazı işlemler kullanırsanız constexpr, bu kod derlenmeyecektir.


8
std::is_same<T, U>::valuesizin yerine daha kısa kullanabilirsiniz:std::is_same_v<T, U>
Fureeish

12

C ++ 17'de varyantları kullanabiliriz .

Kullanmak std::variantiçin başlığı eklemeniz gerekir:

#include <variant>

Bundan sonra, std::variantkodunuzu şu şekilde ekleyebilirsiniz :

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 ve Type nasıl bağlanır?
mabraham

4
Bu cevap birkaç yönden sorunludur. Gerçek hataların yanı sıra ( typeburada Typebir anlam ifade etmeyen tür veya şablonun değeri ) is_same_vbağlamında anlamlı değildir variant. Karşılık gelen "özellik" dir holds_alternative.
Pixelchemist

std::variantburada tamamen gereksiz
tjysdsg

7

Şablonlarınızı aşağıdaki gibi parametrelerine geçirilenlere göre özelleştirebilirsiniz:

template <> void foo<animal> {

}

Bunun, olarak geçirilen türe göre tamamen yeni bir işlev oluşturduğunu unutmayın T. Bu, dağınıklığı azalttığı için genellikle tercih edilir ve esasen ilk etapta şablonlara sahip olmamızın nedenidir.


Hmm. Bu yöntem gerçekten şablon argümanını özelleştirmenin tek tercih edilen yolu mu? Diyelim ki şablon işlevi içinde yönetmem gereken 10 farklı çocuk sınıfım var. İlgili sınıf için gerçekten 10 farklı şablon işlevi yazmam gerekiyor mu? Sanırım burada ana noktayı kaçırıyor olabilirim.
Volkan Güven

Birisi type_traits kullanmak istemiyorsa, bu gerçekten iyi bir fikir gibi geliyor. Birinin bahsettiği gibi, ana mantık, türü belirtmek için fazladan bir bayrak kabul eden farklı bir işlevde yapılabilir ve bu özel bildirim, bayrağı buna göre ayarlayabilir ve diğer tüm argümanları hiçbir şeye dokunmadan doğrudan iletebilir. Yani 10 farklı sınıfın ele alınması gerekiyorsa, temelde 10 farklı işlev tanımı için 10 satırdır. Ancak 1'den fazla şablon değişkeni varsa bu çok karmaşık hale gelecektir.
Harish Ganesan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.