. , , -. Variadic class-templates. :
#include <vector>
#include <string>
#include <iostream>
#include <exception>
using StrCIter = std::string::const_iterator;
void printerHelper(StrCIter& fmtPos, StrCIter fmtEnd, std::vector<std::string>& vec)
{
auto vecIter = vec.begin ();
while(vecIter != vec.end () && fmtPos != fmtEnd)
{
if(*fmtPos == '%' && *(fmtPos + 1) == 's')
{
std::cout << *vecIter++;
fmtPos += 2;
continue;
}
std::cout << *fmtPos++;
}
}
template <typename T>
void printerHelper(StrCIter& fmtPos, StrCIter fmtEnd, const T& value)
{
std::cout << value;
fmtPos += 2;
}
void myPrintfHelper(StrCIter pos, StrCIter end)
{
while(pos != end)
{
if(*pos == '%')
{
throw "More format specifiers than arguments provided!";
}
std::cout << *pos++;
}
}
template <typename Head, typename ... Tail>
void myPrintfHelper(StrCIter pos, StrCIter end, Head&& head, Tail&&... tail)
{
while(pos != end)
{
if(*pos == '%' && *(pos + 1) == 's')
{
printerHelper (pos, end, head);
return myPrintfHelper(pos, end, std::forward<Tail>(tail)...);
}
std::cout << *pos++;
}
}
template <typename ... Args>
void myPrintf(const std::string& format, Args&& ... args)
{
myPrintfHelper (format.begin(), format.end (), std::forward<Args>(args)...);
}
int main()
{
std::vector<std::string> v = {"world", "magic"};
myPrintf("Hello, %s! Welcome to the %s of variadic template %s! This ... is ... C++%s!", "StackOverflow", v, 11);
return 0;
}
, formate, ( %s), , . , ,
printf(), , , .
, Stroustrups printf - std::string string const char*.
, , printHelper, , operator<<(std::ostream&[, ...]), .
All the overload that needs to be done is to adjust the format string iterator setting and print the material when the format specifier is hit. In my two examples, I am doing this ahead of 1 to determine that we are in the format specifier, but there are other ways.
By the way, the conclusion:
Hi StackOverflow! Welcome to the world of variable magic! This ... is ... C ++ 11!