2014-12-09 10 views
15

std::ostream kullanarak, virgülle ayrılmış bir parametre paketini yazdırmanın en kolay yolu nedir?Std :: ostream kullanarak değişken bir parametre paketi yazdırmanın en kolay yolu nedir?

Örnek:

template<typename... Args> 
void doPrint(std::ostream& out, Args... args){ 
    out << args...; // WRONG! What to write here? 
} 

// Usage: 
int main(){ 
    doPrint(std::cout,34,"bla",15); // Should print: 34,bla,15 
} 

Not: Bu << operatörün karşılık gelen bir yük parametresi paketin her türlü uygun olduğu kabul edilebilir.

Ben argümanlar kopyalarını her zaman yapmak ve bunun yerine yönlendirme kullanmak ister gerçek kodda Tabii:

+1

C'de ++ 17, diyelim ki (dışarı << ... <<< args); '. –

+0

Not: Bu bir kopya değil - 'foo << X << Y;' genellikle 'foo << X ile aynı değildir; foo << Y; 'özellikle 'foo' disk üzerinde bir dosya açma gibi yan etkileri olduğunda. – MSalters

+0

@MSalters ayrıca, 'foo << X << Y'' X' ve 'Y' için değerlendirme sırasını belirtmez (C++ 17'den önce), –

cevap

17

Bir daha alternatif: Dolayısıyla, düz işlev çağrısı sözdizimi f(s, x) içine s << x sözdizimi dönüştürmek gerekir

template <typename Arg, typename... Args> 
void doPrint(std::ostream& out, Arg&& arg, Args&&... args) 
{ 
    out << std::forward<Arg>(arg); 
    using expander = int[]; 
    (void)expander{0, (void(out << ',' << std::forward<Args>(args)),0)...}; 
} 

DEMO

+1

Bu en kolay olanı. Sadece garip görünüyor hehe. –

+4

@ GermánDiago http://en.cppreference.com/w/cpp/language/parameter_pack benzer bir örnek veriyor: int dummy [sizeof ... (Ts)] = {(std :: cout << args, 0) ...} '' –

+2

Bir yan not olarak, 'using' bildirgesini atlayabilir ve sadece yazabilirsiniz (void) (int []) {(std :: cout << ',' << std :: ileri (args)), 0) ...}; '. Ayrıca, parantez içindeki ilk sıfıra ya da iç boşluğa ihtiyacınız yok. –

4

zamanki cevabı temel durum için boş bir biri ile, iki ayrı aşırı yükleri tanımlamaktır referanslar, ama sizde fikir edinirsiniz.

Son öğeden sonra bile, her öğeden sonra virgül eklemek isterseniz, out << t << ',' ile out << t'u değiştirin.

Yalnızca iç kısımda virgül, son öğeyi geçmezseniz, virgül yazdırmayan ayrı bir tek argüman aşırı yüklenmeye gereksiniminiz vardır ve genel bir aşırı yük, paketin önünde iki farklı argüman alır, örn .:

template <typename T> 
void doPrint(std::ostream& out, T t) 
{ 
    out << t; 
} 

template <typename T, typename U, typename... Args> 
void doPrint(std::ostream& out, T t, U u, Args... args) 
{ 
    out << t << ','; 
    doPrint(out, u, args...); 
} 
+0

İletim referanslarında biraz detaylandırma yapabilir misiniz?Bu C++ 11 malzemesinde henüz çok sağlam değilim ve parametrelerin kopyalanması gerçekten bir overkill gibi görünüyor. – gexicide

+0

@gexicide: Bu sitede binlerce kopya, sadece arama yapın. Args && ... args' ve std :: forward (args) ... 'ı arıyoruz. –

4

Parametre paketi genişletme yalnızca infix operatörleri için değil, düz işlev çağrılarında çalışır. İstediğin özyinelemeli aramalar ve virgül olmadan

template<class Head> 
void print_args_(std::ostream& s, Head&& head) { 
    s << std::forward<Head>(head); 
} 

template<class Head, class... Tail> 
void print_args_(std::ostream& s, Head&& head, Tail&&... tail) { 
    s << std::forward<Head>(head); 
    print_args_(s, std::forward<Tail>(tail)...); 
} 

template<class... Args> 
void print_args(Args&&... args) { 
    print_args_(std::cout, std::forward<Args>(args)...); 
} 
2

C++ 17, daha kolay bir yol olacak (Kerrek SB tarafından yorumlarda belirtildiği gibi; bu aslında N4606'da, ilk C++ 14 taslağında mevcuttu), fold expressions:

kodu olacaktır:

(out << ... << args); 

ve tanımlarını (((expressionop arg1) op arg2) op arg3) .... op argN eşdeğerdir expression op...op parameter-packbir ikili sol kat olarak adlandırılan deseni.

Ben dış parantez böyle bir ifade-deyimi için mutlaka bulunması düşünüyorum, ama kat ifade başka operatörün bir işlenenlerden ise onlar da gereklidir, ya çok iyi bir fikir :)

İlgili konular