2013-04-15 34 views
5

Variadic templates printf işlevinin çeşitli uygulamaları vardır. Her yerdeDeğişken Şablonlar ve Türleri

void printf(const char* s) { 
    while (*s) { 
    if (*s == '%' && *++s != '%') 
     throw std::runtime_error("invalid format string: missing arguments"); 
    std::cout << *s++; 
    } 
} 

template<typename T, typename... Args> 
void printf(const char* s, const T& value, const Args&... args) { 
    while (*s) { 
    if (*s == '%' && *++s != '%') { 
     std::cout << value; 
     return printf(++s, args...); 
    } 
    std::cout << *s++; 
    } 
    throw std::runtime_error("extra arguments provided to printf"); 
} 

ve bu uygulama güvenli-tip (variadic argümanlar va_arg ile) Normal C değilken olduğu söylenir: birisi bu.

Neden? Tip-güvenli olması ve bu uygulamanın C printf va_arg üzerinde ne gibi avantajları vardır?

+3

Bu sürüm, biçimlendirme bayrakları hakkında hiçbir şey umursamıyor, yalnızca akış işleyicilerinden bir şeyler yazdırıyor. – Xeo

+1

Bu 'T', her zaman gerçekte geçirilen parametrenin tipi olacaktır. Standart printf bilmiyor. –

+1

Bir kenara göre, korkunç bir "printf" uygulamasıdır.Biçim belirleyicileri yok sayar ve yanlış yorumluyor ve hatta geçici değerlerin taşınmasını desteklemiyor! Kısacası, bu tür bir fonksiyondur, fakat ismine rağmen, printf'in geçerli bir uygulaması değildir. İyi bir güvensiz 'printf' güvenli olduğunda 'printf' ile aynı şekilde davranır ve çoğu güvensiz vakada tanımsız olarak başarısız olur. – Yakk

cevap

4

güvenli veya tip-güvenli olmak, programınız düzgün davranır olmadığını Kaynak kodu bakarak söyleyebilirim anlamına gelir.

x'un iyi tanımlanmış bir değere sahip olduğu varsayımıyla std::cout << x ifadesi her zaman doğrudur (ve başlangıçta başlatılmamış); Bu, kaynak koduna bakmayı garanti edebileceğiniz bir şeydir. Örneğin, aşağıdaki kod, veya çalışma zamanı girişi bağlı olarak, doğru olmayabilir: constrast tarafından

, C grubu güvenli olan

int main(int argc, char * argv[]) 
{ 
    if (argc == 3) 
     printf(argv[1], argv[2]); 
} 

, bu doğrudur, ancak ve ancak ilk argüman, tam olarak bir "%s" içeren geçerli bir biçim dizesidir. Başka bir deyişle, doğru bir C programı yazmak mümkündür, ancak sadece kodun denetlenmesiyle doğruluk hakkında akıl yürütmek imkansızdır. printf işlevi böyle bir örnektir. Daha genel olarak, değişken argümanları kabul eden herhangi bir fonksiyon, çalışma zamanı değerlerine göre işaretçileri yayınlayan herhangi bir işlev gibi, büyük olasılıkla güvensizdir.

+0

+1 Daha iyi bir çalışma zamanı girdisine bağımlı yürütme durumu için bu örneği atlamak zor. Ve bunun üstünde mükemmel bir cevap. – WhozCraig

5

Variadic şablon sürümüne ilettiğiniz tüm argümanlar için, türleri derleme zamanında bilinir. Bu bilgi işlev içerisinde korunur. Her nesne daha sonra aşırı yüklü operator<< ile cout'a geçirilir. Geçirilen her tür için bu işlevin ayrı bir aşırı yüklenmesi vardır. Diğer bir deyişle, bir int iletirseniz, ostream::operator<<(int) numaralı telefonu çağırırsanız, bir çift iletirseniz, ostream::operator<<(double) numaralı telefonu çağırır. Yine, tür korunur. Ve bu işlevlerin her biri, her türü uygun bir şekilde işlemek için uzmanlaşmıştır. Bu tip güvenlik.

Ancak, C printf ile hikaye farklıdır. Bu işlev, işlev içinde korunmaz. Biçim dizgisinin içeriğine (çalışma zamanı değeri olabilir) bağlı olarak bunu anlaması gerekir. Bu işlev, argüman türlerini eşleştirmek için doğru format dizesinin aktarıldığını varsaymak zorundadır. Derleyici bunu zorlamaz.

Başka türde bir güvenlik de var ve bu da argüman sayısında. C printf işlevine çok az argüman iletirseniz, biçim dizesiyle eşleşmesi için yeterli değil, tanımlanmamış davranışınız vardır. Variadic şablonla aynı şeyi yaparsanız, istenen olmasa da, teşhis edilmesi çok daha kolay bir sorun olan bir istisna alırsınız.