2016-04-13 35 views
2

Birisi buradaki garip çıkışı açıklayabilir mi?Şablon fonksiyonundan garip çıktının açıklaması

#include <iostream> 
#include <type_traits> 

template <typename T> 
constexpr auto has_foo_impl(int) -> decltype(typename T::foo{}, std::true_type{}); 

template <typename T> 
constexpr auto has_foo_impl(long) -> std::false_type; 

template <typename T> 
constexpr bool has_foo() { return decltype(has_foo_impl<T>(0))::value; } 

template <typename...> struct rank; 

template <typename First, typename... Rest> 
struct rank<First, Rest...> : rank<Rest...> {}; 

template <> struct rank<> {}; 

template <typename T, typename... Rest, typename... Args> 
auto check (rank<T, Rest...>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))> { 
    return T(args...); 
} 

//template <typename T, typename U, typename... Args> 
//auto check (rank<T,U>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))> { 
// return T(args...); 
//} 
// 
//template <typename T, typename... Args> 
//auto check (rank<T>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))> { 
// return T(args...); 
//} 

template <typename... Args> 
auto check (rank<>, Args...) { std::cout << "Nothing found.\n"; } 

template <typename... Ts> 
struct Factory { 
    template <typename... Args> 
    decltype(auto) create (Args... args) const { 
     return check(rank<Ts...>{}, args...); 
    } 
}; 

struct Object {}; 

struct Thing {}; 

struct Blob { 
    using foo = int; 
    Blob (int, double) { print(); } 
    void print() const { std::cout << "Blob\n"; } 
}; 

int main() { 
    Factory<Blob, Object, Thing>().create(4,3.5); // Blob 
    Factory<Object, Blob, Thing>().create(4,3.5); // Nothing found 
    Factory<Object, Thing, Blob>().create(4,3.5); // Nothing found 
} 

Üç kez Blob çıktı görmeyi bekliyorum. check yorumlanmış aşırı yüklemelerini kaldırdığımda, bunu anladım. Tek değişkenli check işlevi yorumladığımları dikkate almamalıdır mı? Sonuçta, rank<First, Rest...>, rank<Rest...>'dan gelir.

Yaptığım aynı işi almak için diğer yolları biliyorum ama bu sıralama yöntemi burada çalışmıyor neden merak ediyorum. Nothing found çıktısı, rank<>'un geçtiği anlamına gelir, yani ara sıralar da geçti.

cevap

4

Yalnızca kiraz az bir ısırık almak.

Aşırı yük çözünürlüğü gerçekleştirilirken, SFINAE çıkarılan aşırı yükü kaldırsa ve şablon argümanlarını çıkartmak için başka (daha az tercih edilen) yollar olsa bile, kullanılabilir işlev şablonlarının her biri şablon argümanlarını yalnızca bir kez çıkarılır.

Yani, verilen: İlk argüman türü olarak rank<Object, Blob, Thing> ile

template <typename T, typename... Rest, typename... Args> 
auto check (rank<T, Rest...>, Args... args) -> std::enable_if_t<has_foo<T>(), decltype(T(args...))>; 

, TObject ve [Blob, Thing] olarak Rest olarak çıkarılır. Ancak bundan sonra SFINAE, sonuçta ortaya çıkan aşırı yükü ortadan kaldırır.

Yorumlanmış aşırı yüklerinizden rahatsız olmanız, çalışmasını olanaklı kılar; çünkü bu, 3 işlev şablonu sağlar, böylece Blob ile birinci, ikinci ve son konumlarda çalışır; ve 3 argümanla test ettiniz. Bu 4. (Example.)

2. pozisyonunda Blob ile Object, Blob, Thing, Whatever için çalışmaz

Ayrıca hiç biraz farklı miras karşı şablon kesinti rütbesine görünen clang, işe yaramaz senin yorumladı aşımı aşırı yüklenmeleri uncommenting . (Example.) Şablon argümanı kesinti için daha fazla fırsat oluşturmak gerekir

; Bir yol özyineleme olabilir (Example):

template <typename T, typename... Rest, typename... Args> 
auto check (rank<T, Rest...>, Args... args) -> std::enable_if_t<!has_foo<T>(), decltype(check(rank<Rest...>{}, args...))> { 
    return check(rank<Rest...>{}, args...); 
} 
+0

@ ecatmur Çok güzel bir yanıt için teşekkürler. Oldukça esrarengiz görünen bu takip sorusuyla ilgilenebilirsiniz: http://stackoverflow.com/questions/36611105/why-template-instantiations-go-on-forever-here – prestokeys