2014-12-09 9 views
15

Jaki jest najłatwiejszy sposób wydrukowania pakietu parametrów, oddzielony przecinkami, przy użyciu std::ostream?Jaki jest najłatwiejszy sposób wydrukowania pakietu parametrów variadic za pomocą std :: ostream?

przykład:

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 
} 

Uwaga: można przyjąć, że odpowiednia przeciążenia operatora << jest dostępna dla wszystkich rodzajów opakowania parametrów.

+1

W C++ 17, powiesz: '(out << ... <<< argumenty);'. –

+0

Uwaga: To nie jest duplikat - 'foo << X << Y;' zazwyczaj nie jest tym samym co 'foo << X; foo << Y; 'zwłaszcza gdy' foo' ma efekty uboczne, takie jak otwarcie pliku na dysku. – MSalters

+0

@MSalters również, 'foo << X << Y' nie określa kolejności oceny' X' i 'Y' (przed C++ 17, to jest) –

Odpowiedz

17

Jeszcze alternatywnym bez rekurencyjnych wywołań i przecinkami gdzie chciałeś:

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

Ten jest najłatwiejszy. Po prostu wygląda dziwnie, hehe. –

+4

@ GermánDiago http://en.cppreference.com/w/cpp/language/parameter_pack daje podobny przykład: 'int dummy [sizeof ... (Ts)] = {(std :: cout << args, 0) ...}; ' –

+2

Na marginesie, możesz pominąć deklarację' using' i po prostu napisać '(void) (int []) {(std :: cout << ',' << std :: forward (args)), 0) ...}; '. Nie potrzebujesz też pierwszego zera w nawiasie klamrowym lub wewnętrznej obsadzie "void". –

4

Zwykle odpowiedź jest zdefiniowanie dwóch odrębnych przeciążeń, z pustym jeden dla przypadku bazowego:

oczywiście w prawdziwym kodzie nie będę wykonywać kopie argumentów za każdym razem i zamiast wykorzystać przekierowania referencje, ale masz pomysł.

Jeśli chcesz dodać przecinki po każdym elemencie, nawet po ostatnim, po prostu zastąp out << t przez out << t << ','.

Jeśli chcesz mieć przecinki od wewnątrz, a nie za ostatnim elementem, potrzebujesz oddzielnego jednobiegowego przeciążenia, które nie drukuje przecinka, a ogólne przeciążenie bierze dwa różne argumenty przed pakietem, tj .:

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

Czy możesz rozwinąć nieco na odniesieniach do przekazywania?Nie jestem zbyt stanowczy w tym C++ 11, ale kopiowanie parametrów naprawdę wydaje się przesadą. – gexicide

+0

@gexicide: tysiące duplikatów na tej stronie, wystarczy przeszukać. Poszukujesz 'Args && ... args' i' std :: forward (args) ... '. –

4

Rozszerzenie zestawu parametrów działa tylko w przypadku wywołań funkcji zwykłych, a nie dla operatorów nawożenia. Stąd trzeba konwertować s << x składnię wywołania funkcji w zwykłym składni f(s, x):

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

W C++ 17, będzie łatwiejszy sposób (o czym wspominał Kerrek SB w komentarzach, był on obecny w N4606, pierwszy szkic po C++ 14), o nazwie fold expressions:

Kod byłoby:

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

a wzór expression op...op parameter-pack nazywany jest lewej binarny krotnie, którego definicja jest równoważna (((expressionop arg1) op arg2) op arg3) .... op argN.

myślę zewnętrzne nawiasy nie są absolutnie niezbędne do ekspresji-oświadczenie jak to, ale jeśli krotnie ekspresja jest operand od innego operatora, a następnie są one albo wymagane, lub bardzo dobry pomysł :)

Powiązane problemy