2017-05-16 17 views
40

tanımında varsayılan türe sahip bir şablonla mücadele ediyor gcc ile bir sorunu saptamak için çok sayıda saat harcadım. Clang'un kaçırmış olabileceği konusunda daha fazla uyarı aramak için kod tabanımızı başka bir derleyiciyle test etmek istedim. Projenin neredeyse yarısının, şablon argümanı kesintisinin başarısızlığı nedeniyle derlenmeyi bırakması beni şaşırttı. Burada davanımı en basit kod parçası haline getirmeyi denedim. GCC'nin tüm sürümleri,

#include <type_traits> 

struct Foo 
{ }; 

// This is a template function declaration, where second template argument declared without a default 
template <typename T, typename> 
void foo(const Foo & foo, T t); 

// This is a template function definition; second template argument now has a default declared 
template <typename T, typename = typename std::enable_if<1>::type> 
void foo(const Foo & foo, T t) 
{ 
} 

int main(int argc, char ** argv) 
{ 
    foo(Foo{}, 1); 
    return 0; 
} 

std::enable_if<1> bir 1 geçiyoruz. Açıkçası, önemi olmayan şeyleri karmaşıklaştırmak için sabit bir değerdir.

Bu kod parçası derler [1] çınlama (4.0 üzerinden 3.4), ICC (16, 17), Visual C++ ile (19.00.23506). Temel olarak, gcc (4.8 - 7.1) dışındaki herhangi bir C++ 11 derleyiciyi bu kod parçasını derlemedim.

Soru şu ki, kim haklı ve kim yanlış burada? gcc standarda göre davranıyor mu?

Açıkçası bu önemli bir konu değildir. Bildirime kolayca std::enable_if'u taşıyabilirim. Tek kurban estetik olurdu. Ancak, uygulamada kütüphane işlevinin kullanıcısı için hemen geçerli olmayan çirkin 100 karakter uzunluğunda std::enable_if kodunun gizlenebilmesi güzel bir şey. godbolt.org üzerinde


Canlı bir örnek.

+2

En.cppreference.com'da [varsayılan şablon argümanları] için (http://en.cppreference.com/w/cpp/language/template_parameters#Default_template_arguments) »Bildirimlerde ve tanımda görünen varsayılan şablon argümanları varsayılan işlev argümanlarına benzer şekilde birleştirilir «. [Varsayılan işlev argümanları] için (http://en.cppreference.com/w/cpp/language/default_arguments) "... işlev bildiriminin parametre listesinde bir parametrenin aşağıdaki sözdizimini kullanarak gösterildiğini gördüm ...« . Eğer bunu doğru olarak yorumluyorsam, beyannamede * varsayılan argümana * sahip olursunuz. https://godbolt.org/g/kXNbYi: –

+0

@HenriMenke, bu ** gcc ** işlevleri için çalışır. Görünüşe göre, ** gcc ** fonksiyonlar ve şablonlar için çifte standartlara sahip ... – GreenScape

+0

@HenriMenke 14.1/10'da "template <...> class A" örneğine bakınız. G ++ 'da olduğu gibi çalışır, ancak bir işlevi bir sınıfla değiştirmezseniz. –

cevap

34

standart diyor ne ([1] sayfa 350):

tanımından öntanımlıyı argümanlar birleştirilmesi ile elde edilen bir şablon beyanı veya tanımıyla kullanıma hazır varsayılan şablon tartışmaların seti (eğer kapsamı) ve kapsamındaki tüm beyanlar aynı şekilde varsayılan fonksiyon argümanlarıdır (8.3.6). [ Örnek:

template<class T1, class T2 = int> class A; 
template<class T1 = int, class T2> class A; 
is equivalent to 
template<class T1 = int, class T2 = int> class A; 

- uç örneği]

Yani GCC burada yanlış. Bildirimlerde varsayılan şablon argümanlarını yoksayar.

Tüm bildirimler değil, yalnızca işlev bildirimleri işlevi. Sınıf şablon bildirimleri tamam şunlardır: godbolt.org


üzerinde

#include <type_traits> 

template <typename T, typename> 
struct Foo; 

template <typename T, typename = typename std::enable_if<1>::type> 
struct Foo 
{ 
    T t; 
}; 

int main() 
{ 
    Foo<int> foo; 
    return 0; 
} 

Canlı örnek Muhtemelen çıkarılabilir nasıl varsayılan olmayan argümanlar doğasından kaynaklanmaktadır. İşlev şablonunda işlev argümanlarından çıkarılır. Sınıf şablonunda bunları açıkça belirtmek zorundayız.

Neyse, bir bug report oluşturduk.

+1

İşlev şablonları için varsayılan şablon argümanları nispeten yenidir (C++ 11). GCC milletlerinin bunu kaçırması şaşırtıcı değil. –

İlgili konular