Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++.moderated > #2577
| From | Daniel Krügler <daniel.kruegler@googlemail.com> |
|---|---|
| Newsgroups | comp.lang.c++.moderated, comp.lang.c++ |
| Subject | Re: C++11 Variadic Templates: Format("I %%% about %%% of %%%","dream", 7, 9) == "I dream about 7 of 9" |
| Date | 2011-11-29 22:33 -0800 |
| Organization | A noiseless patient Spider |
| Message-ID | <jb308c$bjo$1@dont-email.me> (permalink) |
| References | <8ce7855d-ade8-4d83-ad8e-9fec2266c72b@b32g2000yqn.googlegroups.com> |
Cross-posted to 2 groups.
On 2011-11-28 23:31, Andrew Tomazos wrote:
> 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:
Yes, the idea is nice, but let me comment on some parts.
> 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?
Yes, see below.
> #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& ...);
This function template is no-where use. You should get rid of it.
> template<class ... T>
> inline string Format(const string& sFormat)
There is no reason to declare this as a variadic template. Just declare
it as a non-template function:
inline string Format(const string& sFormat)
> {
> size_t iFirstPlaceholderPos = sFormat.find(g_sPlaceholder);
Either use string::size_type or - more preferably auto to determine the
type of iFirstPlaceholderPos. In theory there is no guarantee that
size_t and string::size_type have the same type or even the same maximum
value (which is relevant when using string::npos).
> 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);
Same problem here.
> 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;
> }
In regard to your question, whether an iterative solution is possible:
Yes, at least in the sense that you can serialize your expansions. The
following code demonstrates this:
//----------------------------
#include <string>
#include <sstream>
#include <iostream>
#include <cstddef>
class StringFormatException {};
const std::string g_sPlaceholder("%%%");
struct void_{};
template<class T>
void_ DoFormat(std::ostream& os, const std::string& sFormat,
std::string::size_type& curr, const T& t)
{
auto nextPos = sFormat.find(g_sPlaceholder, curr);
if (nextPos == std::string::npos)
throw StringFormatException();
else
{
os.write(&sFormat.front() + curr, nextPos - curr);
os << t;
curr = nextPos + g_sPlaceholder.size();
}
return {};
}
template <class... Args>
inline std::string Format(const std::string& sFormat, const Args&... args)
{
std::stringstream os;
std::string::size_type curr = 0;
std::initializer_list<void_>{DoFormat(os, sFormat, curr, args)...};
auto nextPos = sFormat.find(g_sPlaceholder, curr);
if (nextPos != std::string::npos)
throw StringFormatException();
if (!sFormat.empty())
os.write(&sFormat.front() + curr, sFormat.size() - curr);
return os.str();
}
// ... Your test main() follows here unchanged
//----------------------------
You may wonder about the astonishing void_ type as well as the
std::initializer_list<void_>{DoFormat(os, sFormat, curr, args)...}
expression.
What I'm realizing here is to create an initializer-list expanded with
sizeof...(Args) expressions that have type void_. Unfortunately I cannot
use void here, because this is no object type. Even more unfortunate is,
that I cannot use a function call e.g.
template<class... T>
void swallow(T&&...){}
...
swallow(DoFormat(os, sFormat, curr, args)...);
This will compile, but since the order of the evaluation of function
arguments is not determined, there is no guarantee that this works in a
portable manner, because each function call modifies the arguments os
and curr. There exists a special rule in C++11 that ensures that
initializer-lists are evaluated in a strict order, this is the reason
why I'm creating an otherwise unused std::initializer_list<void_> here.
As elegant as it looks, I'm very unhappy about the need to create such a
hack here. It would be great, if there would exist a further expansion
pattern that allows me to write e.g.
DoFormat(os, sFormat, curr, args)...;
such that DoFormat may have type void as well.
I hope nonetheless that this suggestion gives you another idea how to
proceed.
HTH & Greetings from Bremen,
Daniel Krügler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to comp.lang.c++.moderated | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
C++11 Variadic Templates: Format("I %%% about %%% of %%%","dream", 7, 9) == "I dream about 7 of 9" Andrew Tomazos <andrew@tomazos.com> - 2011-11-28 14:31 -0800
Re: C++11 Variadic Templates: Format("I %%% about %%% of %%%","dream", 7, 9) == "I dream about 7 of 9" legalize+jeeves@mail.xmission.com (Richard) - 2011-11-28 22:58 -0800
Re: C++11 Variadic Templates: Format("I %%% about %%% of %%%","dream", 7, 9) == "I dream about 7 of 9" "news" <newsmaster@tdcnet.fi> - 2011-11-29 22:24 -0800
Re: C++11 Variadic Templates: Format("I %%% about %%% of %%%","dream", 7, 9) == "I dream about 7 of 9" legalize+jeeves@mail.xmission.com (Richard) - 2011-11-30 12:45 -0800
Re: C++11 Variadic Templates: Format("I %%% about %%% of %%%","dream", 7, 9) == "I dream about 7 of 9" Andrew Tomazos <andrew@tomazos.com> - 2011-11-29 22:26 -0800
Re: C++11 Variadic Templates: Format("I %%% about %%% of %%%","dream", 7, 9) == "I dream about 7 of 9" Daniel Krügler <daniel.kruegler@googlemail.com> - 2011-11-29 22:33 -0800
size_type and size_t Seungbeom Kim <musiphil@bawi.org> - 2011-12-02 05:54 -0800
Re: size_type and size_t Jean-Marc Bourguet <jm@bourguet.org> - 2011-12-02 22:33 -0800
Re: size_type and size_t Daniel Krügler <daniel.kruegler@googlemail.com> - 2011-12-02 22:35 -0800
csiph-web