2

I'm searching for an sprintf in c++.

I want to build a mysql query string but if I do it like (max_limit is an const int)

std::string query = "select * from bla limit " + max_limit;

The query wont work.

Taryn
  • 242,637
  • 56
  • 362
  • 405
Roby
  • 2,011
  • 4
  • 28
  • 55
  • 6
    not directly answering your question, but consider using `prepared statements`. You can then pass the `max_limit` as an argument, and it is generally better in many ways. – davka May 11 '11 at 11:22
  • If you want to write a multi-language source file (both `C` and `C++`) I suggest you do not use `::` or `namespace` or `<<` (except if it means bitwise shift) or `string` ... – pmg May 11 '11 at 11:30
  • I've found Boost Format (suggested by @mkaes below) to be the best alternative. It's very flexible, and has a fairly decent syntax. – gavinb Jul 16 '13 at 04:39

4 Answers4

9

In C++11, this has been made too easy. Use std::to_string() as:

std::string query = "select * from bla limit " + std::to_string(max_limit);

Done!


OLD SOLUTION, for those who still use C++03.

Use stringbuilder and create std::string on the fly as:

std::string query = stringbuilder() << "select * from bla limit " << max_limit;

where stringbuilder is implemented as:

struct stringbuilder
{
   std::stringstream ss;
   template<typename T>
   stringbuilder & operator << (const T &data)
   {
        ss << data;
        return *this;
   }
   operator std::string() { return ss.str(); }
};

You can use stringbuilder in many different ways, such as:

std::string g(int m, int n) 
{
    //create string on the fly and returns it
    if ( m < n )
        return stringbuilder() << m << " is less than " << n ;
    return stringbuilder() << n << " is less than " << m ;
}

void f(const std::string & s );

//call f while creating string on the fly and passing it to the function
f(stringbuilder() << '{' << pc << '}' ); //passed as std::string

//this is my most favorite line
std::string s = stringbuilder() << 23  << " is greater than " << 5 ;

See demo at ideone : http://ideone.com/J995r

And see my blog on this : Create string on the fly just in one line

Raxvan
  • 6,257
  • 2
  • 25
  • 46
Nawaz
  • 353,942
  • 115
  • 666
  • 851
6

You don't want sprintf, it doesn't work with strings. Something like this:

#include <sstream>
#include <string>

template <typename T>
std::string Str( const T & t ) {
    std::ostringstream os;
    os << t;
    return os.str();
}

will do the job. You can then say:

std::string query = "select * from bla limit " + Str( max_limit );
  • surely it's simpler to construct as `std::ostringstream str("select * from bla limit "); str << max_limit;` then the query is simply `str.str()`... – Nim May 11 '11 at 11:35
  • No, it's not simpler, it is a lot more typing, assuming he wants to create strings like this all over the place. –  May 11 '11 at 11:40
  • 2
    it's not as clear cut as that, depends on how queries use parameters, I wouldn't just dismiss as "more typing"... it doesn't matter anyway, the point is to highlight `std::ostringstream`. – Nim May 11 '11 at 11:52
4

Maybe you want to take a look at the boost::format lib. It provides the syntax of sprintf with the convenience of c++.
So your example would be:

std::string str = (boost::format("select * from bla limit %d") % max_limit).str();
mkaes
  • 13,781
  • 10
  • 52
  • 72
0

Or just use a macro? #define QueryString(msg) ((static_cast<std::ostringstream&>(std::ostringstream().seekp(0, std::ios_base::cur)<<msg)).str())

Usage: std::string query = QueryString("select * from mytable where x="<<30);

Vite Falcon
  • 6,575
  • 3
  • 30
  • 48
  • To my mind this seems to be worse than the template solutions proposed. – Flexo May 11 '11 at 16:17
  • @awoodland: care to explain why? – Vite Falcon May 11 '11 at 16:37
  • Templates were basically developed to overcome the short comings of macros. Using macros instead of templates here doesn't seem to add any value, but it does encourage cramming everything on one line, obfuscation and invite a whole class accidental subtle bug introductions in the future that wouldn't be possible with templates. – Flexo May 11 '11 at 16:46
  • Did you notice that I'm ACTUALLY using an STL class there? The macro IS based on template. All it does is make things easier for the programmer. That is, instead of writing `std::ostringstream stream;stream<<"Answer to life is "<<42;string s = stream.str()` It does it by `string s = QueryString("Answer to life is "<<42);`. I really don't see your point. – Vite Falcon May 11 '11 at 17:02
  • I would like it if you could mention one such scenario, where there's a bug in the above code. It would be a win-win situation if you could, because then you prove your point and I get to learn something new. – Vite Falcon May 11 '11 at 17:11
  • The problem from my POV is that even though what you have there right now is solid, somewhere down the line someone will be tempted to modify the macro to do one or more of the following things. a) evaluate msg more than once, which could subtly cause undefined behaviour or unintended side-effects b) make msg be more than just an int in such a way that the meaning of the expression either accidentally gets changed or (at best) gives a really confusing error message. My experience has been that it's just not worth that risk when a template would do the job equally well. – Flexo May 11 '11 at 18:10
  • Ok... I'm lost!.... (a) evaluate msg more than once?.... (b) make msg be more than just an int?... Can you please elaborate? Editing the code can result in any number of errors, be it a macro or a template class. You're still not providing a solid answer (or even close to one). – Vite Falcon May 11 '11 at 19:27
  • There are a number of well known scenarios where macros that seem good initially can lead to bad things later in the lifecycle of some software. Because of this I live by the rule "don't use a macro for anything a template (or inlined function) can do just as well". The bad things I'm talking about are: [Evil #1](http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.5), [Evil #2](http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.4), [Evil #3](http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.5), – Flexo May 11 '11 at 20:57
  • [Evil #4](http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6). None of them are directly a problem as it stands with your proposed solution right now, but it's vastly easier for them to accidentally become problematic during the software lifecycle. Why deliberately use a poor tool without a compelling reason when there's a better tool for the job? It's like using C-style casts instead of C++ style ones in C++ code for no reason. All it can ever do is mask errors. There are somethings that can't be done sensibly without macros, but AFAIK this isn't one. – Flexo May 11 '11 at 21:03
  • If someone's using macros beyond include guards in some code I'm asked to review IMHO the onus is on them to justify why it's not using a template/inline. Speed is very unlikely to be a reason, as is maintainability or readability. "You just can't do that with templates" is a fairly common justification, but not the only one. – Flexo May 11 '11 at 21:09
  • All I'm asking is are ANY of those **applicable** to this particular macro. I know macros in general have some issues. In fact, using C++, if you don't know what you're doing is going to throw random results on your face. That doesn't mean using C++ is evil. My point is, WHAT IS WRONG WITH THIS MACRO????... NOT IN GENERAL! – Vite Falcon May 11 '11 at 22:13
  • 1
    I didn't down vote it because it's not terrible I didn't up vote it because it's not best practice. In my view the problems are 1) You've deliberately tried to make it not look like a macro in most naming conventions. 2) Any syntax errors from usage *will* be confusing to any user who hasn't read the definition of the macro. 3) Using a macro has forced you to use an unnatural layout, which makes it harder to read the macro 4) There is a very real risk that someone a year down the road maintaining this will introduce a double evaluation bug adding a new feature or fixing some other problem. – Flexo May 11 '11 at 22:27
  • 2) Is related to 1) also. 3) means you had to add a static cast in there which complicates in unnecessarily. At the end of the day I was trying to be helpful and point out why I didn't think this deserved upvoting compared to the others I voted for. If you included a strong argument why doing it using a macro was better than the other suggestions I might have been persuaded. It's "clever" doing it as just one statement, but I don't think it's maintainable or justified in this context and I can't see anything to convince me otherwise. – Flexo May 11 '11 at 22:30