“……” Belirtecinin anlamı nedir? yani parametre paketinde çift üç nokta operatörü


110

Gcc'nin yeni C ++ 11 başlıklarının mevcut uygulamasına göz atarken, "......" belirtecine rastladım. Aşağıdaki kodun iyi derlendiğini [ideone.com aracılığıyla] kontrol edebilirsiniz.

template <typename T>
struct X
{ /* ... */ };

template <typename T, typename ... U>
struct X<T(U......)> // this line is the important one
{ /* ... */ };

Peki bu simgenin anlamı nedir?

edit: Görünüşe göre soru başlığındaki "......" "..." şeklinde kesilmiş, gerçekten "......" demek istedim. :)


ipucu: ...ardından gelir ....
Alexandre C.

5
Daha çok U...takip etmek gibi değil mi ...? Yine de çok tuhaf.
edA-qa mort-ora-y

1
Not: Bu bulunabilir <functional>ve <type_traits>her zaman bir şablon parametresinin içine bir işlev bağımsız değişken listesinin bağlamında,.
Potatoswatter

Başlığa takılıp kalmamı sağlamanın tek yolu arasına bir boşluk koymaktı ... umarım okuyucular için daha anlaşılır olur.
Matthieu M.

@Matthieu M .: Teşekkürler, çok daha iyi!
Vitus

Yanıtlar:


79

Bu tuhaflığın her örneği, normal tek bir üç nokta vakasıyla eşleştirilir.

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...) const>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......) const>
    { typedef _Res result_type; };

Benim tahminim, çift elips anlam olarak benzerdir _ArgTypes..., ..., yani bir değişken şablon genişletmesi ve ardından bir C-tarzı vararg listesi.

İşte bu teoriyi destekleyen bir test … Sanırım şimdiye kadarki en kötü sözde operatör için yeni bir kazananımız var.

Düzenleme: Bu uyumlu görünüyor. §8.3.5 / 3, parametre listesini aşağıdaki gibi oluşturmanın bir yolunu açıklar:

parametre bildirim listesi tercih ... tercih

Dolayısıyla, çift üç nokta, bir parametre paketi ile biten bir parametre bildirim listesi ve ardından başka bir üç nokta ile oluşturulur.

Virgül tamamen isteğe bağlıdır; §8.3.5 / 4 diyor ki

Sözdizimsel olarak doğru olduğunda ve "..." bir soyut bildiricinin parçası olmadığında, ", ...", "..." ile eşanlamlıdır.

Bu ise , bir arka-Bildiricisi içinde [değiştir] ama Johannes bir parametre bildiriminin içinde soyut-Bildiricisi atıfta olduğu iyi bir noktasıdır. Neden "parametre bildiriminin parçası" demediklerini ve bu cümlenin neden sadece bilgilendirici bir not olmadığını merak ediyorum ...

Ayrıca, va_begin()in <cstdarg>, varargs listesinden önce bir parametre gerektirir, bu nedenle f(...)C ++ tarafından özel olarak izin verilen prototip işe yaramaz. C99 ile çapraz referans, düz C'de yasadışıdır. Yani, bu çok tuhaf.

Kullanım notu

İstek üzerine, burada çift ​​üç nokta için bir gösterim bulunmaktadır:

#include <cstdio>
#include <string>

template< typename T >
T const &printf_helper( T const &x )
    { return x; }

char const *printf_helper( std::string const &x )
    { return x.c_str(); }

template< typename ... Req, typename ... Given >
int wrap_printf( int (*fn)( Req... ... ), Given ... args ) {
    return fn( printf_helper( args ) ... );
}

int main() {
    wrap_printf( &std::printf, "Hello %s\n", std::string( "world!" ) );
    wrap_printf( &std::fprintf, stderr, std::string( "Error %d" ), 5 );
}

Evet bu doğru. T (U ..., ...) yine de iyi derler; belki biraz yer kazanmak istediler. :)
Vitus

1
Ama bu ne anlama geliyor? Ve derleyici _ArgTypes'in nerede bittiğini ve bazı "ekstra" parametrelerin nerede başladığını nasıl söyleyebilir?
Bo Persson

12
@Bo Persson: std::is_function'nin valuefonksiyonu C birini varargs ve T (U ...) çünkü olsa bile doğru olması gerekir değil böyle bir işlev için maç, bu delilik gerekir. Örneğin int f (int, char, ...), T (U ......) ile T = int, U = {int, char} ve "..." varargs jetonuyla tam olarak eşleşir.
Vitus

4
"Bu ise > onlar aynı parametre türü listesinin son parametrenin soyut Bildiricisi parçası olmayan anlamına - soyut-Bildiricisi içinde". Örneğin void (int...)burada, ...soyut bildiricinin parçası değildir int, dolayısıyla eşanlamlıdır void(int, ...). Eğer yazarsanız void(T...)ve Tbir şablon parametre paketiyseniz, ...soyut bildiricinin bir parçası olursunuz ve bu nedenle void(T, ...).
Johannes Schaub - litb

2
"Ayrıca, <cstdarg> içindeki va_begin (), varargs listesinden önce bir parametre gerektirir, bu nedenle C ++ tarafından özel olarak izin verilen f (...) prototipi işe yaramaz." - Hangi argümanların geçtiğini bilmek istiyorsan, bu işe yaramaz. f(...)bu bilginin gerekli olmadığı (ve işlevin gerçekten çağrılmadığı) şablon meta programlamada bir geri dönüş işlevi aşırı yüklemesi olarak yoğun bir şekilde kullanılır.

4

vs2015 üzerinde, şablon sürümünde virgül ayırmak önemlidir:

    template <typename T, typename ... U>
    struct X<T(U...,...)> {};// this line is the important one

örnek bir örnek:

    X<int(int...)> my_va_func;

Saygılarımızla, FM.


Bunu ben de fark ettim, hala oluyor. Developercommunity.visualstudio.com/content/problem/437260/… adresinde hata raporu .
egyik

Bunu bildiğim iyi oldu. Bununla ilgili standartlara atıf veya alıntı var mı?
Red.Wave

.سلام ببخشید نمیدانم
egyik

Bu halka açık bir forumdur. İnsanların ne düşündüğünüzü okumasına izin verin. PLZ, özel mesajlar için yerel dili korur. سپاس.
Red.Wave

Tamam ozaman. Standart konusunda bir uzman değilim - bence başkaları bunu yukarıda biraz ayrıntıyla ele aldı. Microsoft sorun raporu hakkında yorum yapmak isteyen varsa, o zaman önceliğini artırabilir. Rapor, clang ve gcc'nin VC ++ 'nın yapmadığı şeye izin verdiğini gösteriyor, bu yüzden muhtemelen oldukça güçlü bir zeminde olduğumuzu düşünüyorum.
egyik
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.