2013-06-07 20 views
7

C++ (11) <type_traits>'u nasıl kullanacağımı anlamaya çalışıyorum. Ben GCC şablon parametresi U anlamak neden hiçbir ipucu varŞablon Bağımsız Değişken Türü Kesinti Başarısız Olduğu C++ 11 <type_traits>

/home/per/f.cpp: In function ‘int main(int, const char**, const char**)’: 
/home/per/f.cpp:15:23: error: no matching function for call to ‘add(unsigned int&, int&)’ 
    auto a = add(ui, i); 
        ^
/home/per/f.cpp:15:23: note: candidate is: 
/home/per/f.cpp:5:10: note: template<class U, class S> U add(typename std::enable_if<std::is_unsigned<U>::value, U>::type, typename std::enable_if<std::is_signed<S>::value, S>::type) 
inline U add(typename std::enable_if<std::is_unsigned<U>::value,U>::type a, 
     ^
/home/per/f.cpp:5:10: note: template argument deduction/substitution failed: 
/home/per/f.cpp:15:23: note: couldn't deduce template parameter ‘U’ 
    auto a = add(ui, i); 
        ^

olarak GCC 4.8.1 o hataları ile derlenen

İşte benim önemsiz test programı

#include <type_traits> 

template<class U, class S> 
inline U add(typename std::enable_if<std::is_unsigned<U>::value,U>::type a, 
      typename std::enable_if<std::is_signed <S>::value,S>::type b) 
{ 
    return a + b; 
} 

int main(int argc, const char * argv[], const char * envp[]) 
{ 
    unsigned int ui; 
    int i; 
    auto a = add(ui, i); 
    return 0; 
} 

bu. Kodumun hangi bilginin eksik olduğunu bilen var mı? C++ 11'de ilk argüman olarak imzasız bir integral türü alan ve integral türünü ikinci olarak imzalayan bir program nasıl yazarım?

+0

Sen decuce olamaz türleri 'bir nitelik kazanıyor sol ::'. –

+0

** 14.8.2.5 Şablon argümanlarının bir türden çıkarılması [temp.deduct.type] ** 5 Çıkarılamayan bağlamlar şunlardır: - Nitelikli bir tanım kullanılarak oluşturulan bir türün iç içe-isim-türü. – TemplateRex

+0

Tüm güzel yorumlar ve cevaplar için teşekkürler! –

cevap

13

typename std::enable_if<std::is_unsigned<U>::value,U>::type, çıkarılabilir bir bağlam değildir. Bundan U'u çıkarmak için derleyicinin std::enable_if'un ters işlemini uygulama yeteneğine ihtiyacı olacaktır. Çok zor görünmüyor, bu doğru değil, çünkü enable_if gibi basit bir şeyden bahsediyorsunuz. Her özelliğin bunu gerektirmesi imkansız olurdu, bu yüzden C++ sadece güzel oynar ve herhangi bir garip kural istisnası yapmaz: Genel olarak indirilemez, bunun içinde çıkarılabilir değildir.

yerine bu şekilde yapabilirsiniz: bu stili desteklemeyen

template<class U, class S, 
     EnableIf<std::is_unsigned<U>, std::is_signed<S>>...> 
     // see http://flamingdangerzone.com/cxx11/2012/06/01/almost-static-if.html 
U add(U a, S b) 

Ya derleyiciler

düzgün sadece ekstra temerrüde argüman ekleyebilirsiniz:

template<class U, class S> 
U add(U a, S b, 
     typename std::enable_if<std::is_unsigned<U>::value 
      && std::is_signed<S>::value,void>::type* = nullptr) 

... ya dönüş tipi ile uğraşmak.

template<class U, class S> 
typename std::enable_if<std::is_unsigned<U>::value 
    && std::is_signed<S>::value,U>::type 
add(U a, S b) 
+0

vay ...BU ne yapıyor? typename std :: enable_if :: değeri && std :: is_signed :: değer, void> :: type * = nullptr'. işaretçi için rengin? –

2

"Nestled typedef" ifadesinden bir şablon parametresi çıkartmak mümkün değildir. Yani,'u some_template<U>'dan çıkarmak mümkündür, ancak some_template<U>::type'dan değil.

Derleyici, some_template tüm (sonsuz!) Örneklerini numaralandıramıyor ve bunların hangisinin iç içe yazılanların gerçek argüman türüne eşit olduğunu göremiyor.

3

'den önce tip türlerini belirlemeniz gerekmektedir.

Olmalıdır: Sen derleyici U ve S anlamak için bir şans vermiyorsun

template <typename U, typename S> 
typename std::enable_if<std::is_unsigned<U>::value && 
         std::is_signed<S>::value>, U>::type 
add(U u, S s) 
{ 
    // ... 
} 
7

. Sen aşağıdaki gibi işlevini yeniden ve şablon parametre listesinde SFINAE kontrolleri taşıyabilirsiniz:

İşte
template<class U, class S, 
    typename std::enable_if<std::is_unsigned<U>::value && 
          std::is_signed <S>::value 
     >::type* = nullptr> 
inline U add(U a, S b) 
{ 
    return a + b; 
} 

bir live example olduğunu.

2

Dene:

template<class U, class S> 
typename std::enable_if<std::is_unsigned<U>::value && std::is_signed<S>,U>::type 
add(U a , S b) 
{ 
    return a + b; 
} 
+0

Şahsen, dönüş türünde enable_if yazmayı tercih ediyorum, çünkü bu işlev bildirimini çok net gösteriyor. Ek olarak, şablon kesinti çalışmaları yapar (Sizin durumunuzda olduğu gibi). – Manu343726

+0

** inline ** anahtar sözcüğünün kullanılmasından kaçının. C++ derleyici, daha verimli olduğunu düşünürse her işlevi devreye sokar. ** Inline ** yazmış olsanız bile olmasın. Ve hatta ** satır içi ** koyarsanız, eğer derleyici bu fonksiyonun etkin olmadığının inline olduğunu düşünürse, bu fonksiyonun yerini almaz. Yani, ** satır içi ** yazmayın. *** Siz derleyiciden daha iyi bir iyileştirici değilsiniz ***. Basit ve açık kod yazın ve derleyicinin işini yapmasına izin verin. – Manu343726