enable_if
Sınıf
SFINAE aşırı yükleme çözümlemesi için bir türün örneğini koşullu olarak oluşturur. İç içe typedefenable_if<Condition,Type>::type
, ise ve yalnızca ise Condition
için Type
bir eş anlamlıdırtrue
.
Sözdizimi
template <bool B, class T = void>
struct enable_if;
Parametreler
B
Sonuçta elde edilen türün varlığını belirleyen değer.
T
ise B
örneği oluşturacak tür.true
Açıklamalar
ise B
true
, için enable_if<B, T>
eş anlamlı olan "type" adlı iç içe bir tür tanımına T
sahiptir.
ise B
false
, enable_if<B, T>
"type" adlı iç içe bir tür tanımına sahip değildir.
Bu diğer ad şablonu sağlanır:
template <bool B, class T = void>
using enable_if_t = typename enable_if<B,T>::type;
C++ dilinde şablon parametrelerinin değiştirme hatası kendi içinde bir hata değildir; bu SFINAE olarak adlandırılır (değiştirme hatası bir hata değildir). Genellikle, enable_if
bir tanımın başka bir tanım yerine reddedilmesi için aşırı yükleme çözümlemesinden adayları kaldırmak için kullanılır; yani aşırı yükleme kümesini kaldırır. Bu, SFINAE davranışına uygundur. SFINAE hakkında daha fazla bilgi için bkz . Değiştirme hatası Wikipedia'da hata değil.
Dört örnek senaryo aşağıda verilmiştir:
- Senaryo 1: bir işlevin dönüş türünü sarmalama:
template <your_stuff>
typename enable_if<your_condition, your_return_type>::type
yourfunction(args) {// ...
}
// The alias template makes it more concise:
template <your_stuff>
enable_if_t<your_condition, your_return_type>
yourfunction(args) {// ...
}
- Senaryo 2: Varsayılan bağımsız değişkeni olan bir işlev parametresi ekleme:
template <your_stuff>
your_return_type_if_present
yourfunction(args, enable_if_t<your condition, FOO> = BAR) {// ...
}
- Senaryo 3: Varsayılan bağımsız değişkeni olan bir şablon parametresi ekleme:
template <your_stuff, typename Dummy = enable_if_t<your_condition>>
rest_of_function_declaration_goes_here
- Senaryo 4: İşlevinizin şablonlanmamış bir bağımsız değişkeni varsa, türünü sarmalayabilirsiniz:
template <typename T>
void your_function(const T& t,
enable_if_t<is_something<T>::value, const string&>
s) {// ...
}
Senaryo 1, dönüş türleri olmadığından oluşturucular ve dönüştürme işleçleriyle çalışmaz.
Senaryo 2 parametresini adsız bırakır. diyebilirsiniz ::type Dummy = BAR
, ancak ad Dummy
ilgisizdir ve bir ad vermek büyük olasılıkla "başvurulmayan parametre" uyarısı tetikleyebilir. bir FOO
işlev parametresi türü ve BAR
varsayılan bağımsız değişken seçmeniz gerekir. ve 0
diyebilirsinizint
, ancak kodunuzun kullanıcıları işleve yanlışlıkla yoksayılacak ek bir tamsayı geçirebilir. Bunun yerine ve 0
nullptr
veya seçeneğini kullanmanızı void **
öneririz çünkü neredeyse hiçbir şey dönüştürülebilir void **
değildir:
template <your_stuff>
your_return_type_if_present
yourfunction(args, typename enable_if<your_condition, void **>::type = nullptr) {// ...
}
Senaryo 2, sıradan oluşturucular için de çalışır. Ancak, ek parametreler alamadığı için dönüştürme işleçleri için çalışmaz. Ayrıca, oluşturucular için variadic
de çalışmaz çünkü ek parametreler eklemek işlev parametre paketinin çıkarılmayan bir bağlam olmasını sağlar ve böylece amacını enable_if
yener.
Senaryo 3, adını Dummy
kullanır, ancak isteğe bağlıdır. Yalnızca " " typename = typename
" işe yarayabilir, ancak bunun garip göründüğünü düşünüyorsanız "sahte" bir ad kullanabilirsiniz; işlev tanımında da kullanılabilecek bir ad kullanmayın. için bir tür enable_if
vermezseniz, varsayılan olarak geçersiz olur ve ne olduğu sizin için önemli Dummy
olmadığından bu son derece mantıklıdır. Bu, dönüştürme işleçleri ve variadic
oluşturucular da dahil olmak üzere her şey için çalışır.
Senaryo 4, dönüş türleri olmayan oluşturucularda çalışır ve böylece Senaryo 1'in sarmalama sınırlamasını çözer. Ancak, Senaryo 4 her zaman kullanılamayan şablonlanmamış işlev bağımsız değişkenleriyle sınırlıdır. (Şablonlu işlev bağımsız değişkeninde Senaryo 4 kullanıldığında, şablon bağımsız değişkeni kesintisi üzerinde çalışmayı engeller.)
enable_if
güçlüdür, ancak kötüye kullanıldığında da tehlikelidir. Amacı aşırı yükleme çözümünden önce adayları yok etmek olduğundan, kötüye kullanıldığında etkileri çok kafa karıştırıcı olabilir. İşte birkaç öneri:
Derleme zamanında uygulamalar arasında seçim yapmak için kullanmayın
enable_if
. için bir tane yazmayın ve için başka bir taneenable_if
CONDITION
yazmayın!CONDITION
. Bunun yerine, verilen yineleyicilerin güçlü yanlarına bağlı olarak uygulamaları seçen bir algoritma gibi bir etiket dağıtım deseni kullanın.Gereksinimleri zorunlu kılmak için kullanmayın
enable_if
. Şablon parametrelerini doğrulamak istiyorsanız ve doğrulama başarısız olursa, başka bir uygulama seçmek yerine bir hataya neden olursa kullanınstatic_assert
.Aksi takdirde iyi kodu belirsiz hale getiren bir aşırı yükleme kümeniz olduğunda kullanın
enable_if
. Çoğu zaman, bu örtük olarak oluşturucuları dönüştürme sırasında oluşur.
Örnek
Bu örnekte, C++ Standart Kitaplığı şablon işlevinin std::make_pair()
enable_if
avantajlarından nasıl yararlanır açıklanmaktadır.
void func(const pair<int, int>&);
void func(const pair<string, string>&);
func(make_pair("foo", "bar"));
Bu örnekte, make_pair("foo", "bar")
döndürür pair<const char *, const char *>
. Aşırı yükleme çözümlemesi, hangisini func()
istediğinizi belirlemeli. pair<A, B>
' den pair<X, Y>
örtük olarak dönüştüren bir oluşturucuya sahiptir. Bu yeni bir şey değil; C++98 sürümündeydi. Ancak, C++98/03'te, örtük olarak dönüştüren oluşturucunun imzası, olsa bile pair<int, int>(const pair<const char *, const char *>&)
her zaman vardır. Aşırı yükleme çözümlemesi, bu oluşturucunun örneğini oluşturma girişiminin, örtük olarak dönüştürülebilir int
olmadığından korkunç bir şekilde const char *
patlamasına dikkat etmez; işlev tanımlarının örneği başlatılmadan önce yalnızca imzalara bakar. Bu nedenle, hem hem de pair<int, int>
pair<string, string>
'ye dönüştürmek pair<const char *, const char *>
için imzalar mevcut olduğundan örnek kod belirsizdir.
C++11, yalnızca örtük olarak dönüştürülebilir olduğunda ve const Y&
örtük olarak dönüştürülebilir olduğunda const X&
var olduğundan emin olmak pair<A, B>(const pair<X, Y>&)
için B
A
kullanarak enable_if
bu belirsizliği çözdü. Bu, aşırı yükleme çözümlemesinin dönüştürülebilir pair<const char *, const char *>
pair<int, int>
olmadığını ve aldığı pair<string, string>
aşırı yüklemenin uygulanabilir olduğunu belirlemesine olanak tanır.
Gereksinimler
Üstbilgi: <type_traits>
Ad alanı: std