C++11 Variadic Templates: Format("I %%% about %%% of %%%","dream", 7,9) == "I dream about 7 of 9"

A

Andrew Tomazos

I wanted to write a function that takes a string containing a number
of placeholders and a corresponding number of other parameters
(perhaps non-pod) and returns a string with the placeholders replaced
with stringified versions of the parameters:

For example:

Format("I %%% about %%% of %%%","dream", 7, 9)

....would evaluate to...

"I dream about 7 of 9"

....in a similar way to what...

ostringstream os;
os << "I " << "dream" << " about " << 7 << " of " << 9;
return os.str();

....would do.

I'm using gcc 4.6 in -std=c++0x mode so Variadic Templates are
available.

I haven't used Variadic Templates before. My first draft is below. It
appears to work, but it's using a linear recursion. My question is,
is there a way to write it iteratively?

Basically in my recursive solution I define...

Format(s):
output(s)

....as the base case and then...

Format(s, head, tail...):
divide s into three substrings: (eg "foo %%% bar %%% baz")
1. before_first_placeholder (eg "foo ")
2. first_placeholder (eg "%%%")
3. after_first_placeholder (eg " bar %%% baz")

output(before_first_placeholder)
output(head)
output(Format(after_first_placeholder, tail))

....as the recursive case.

Working code and a test case is below. Feedback/thoughts appreciated.

============================ CUT HERE
==========================================
// (C) 2011, Andrew Tomazos <http://www.tomazos.com>

#include <string>
#include <sstream>
#include <iostream>

using namespace std;

class StringFormatException {};

const string g_sPlaceholder("%%%");

template <class ... T>
inline string Format(const string& sFormat, const T& ...);

template <class ... T>
inline string Format(const string& sFormat)
{
size_t iFirstPlaceholderPos = sFormat.find(g_sPlaceholder);

if (iFirstPlaceholderPos != string::npos)
throw StringFormatException();

return sFormat;
}

template <class Head, class ... Tail>
inline string Format(const string& sFormat, const Head& head, const
Tail& ... tail)
{
stringstream os;

size_t iFirstPlaceholderPos = sFormat.find(g_sPlaceholder);

if (iFirstPlaceholderPos == string::npos)
throw StringFormatException();
else
{
string sFront(sFormat, 0, iFirstPlaceholderPos);
string sBack(sFormat, iFirstPlaceholderPos +
g_sPlaceholder.size());

os << sFront << head << Format(sBack, tail ... );
}

return os.str();
}

int main()
{
if (Format("I %%% about %%% of %%%","dream", 7, 9) == "I dream
about 7 of 9")
cout << "pass" << endl;
else
cout << "fail" << endl;

return 0;
}
============================ CUT HERE
==========================================

Tested as follows:
$ cat > test.cpp
<paste above>
$ g++ --version
g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
$ g++ -std=c++0x test.cpp
$ a.out
pass

Enjoy,
Andrew.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top