I'm getting the following error when I compile the following code on Visual Studio 2008 / Windows SDK 7
const UINT a_uint;
UINT result;
throw std::runtime_error( std::string("we did ") + a_uint +
" and got " + result );
Ironically, I ended up with this result:
error C2782: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(
const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem
)' : template parameter '_Elem' is ambiguous
Can someone explain why the error message doesn't explain the real problem (that there is no operator for +ing ints to strings)?
You can reduce that to this
template<typename T>
void f(T, T);
int main() {
f('0', 0); // is T int or char?
}
You try to add an unsigned int to a string. That does not make sense, and the std::string class does not need to take any precautions to add implicit conversions to char here because that would hide such potential programming bugs.
Try to convert the unsigned int to std::string into a decimal/hexadecimal/octal/etc form and then concatenate (you can do that using std::ostringstream or boost::lexical_cast) or fix the bug in other ways you see fit.
Use stringstream (defined in the sstream header) to compose the error message:
std::stringstream ss;
ss << "we did " << a_uint << " and got " << result;
throw std::runtime_error(ss.str());
To a std::string, you can only add other std::strings, ASCIIZ text at an address specified by a const char*, and individual char-acters.
To concatenate other types, you can:
use a stream:
std::ostringstream oss;
oss << "we did " << a_uint << " and got " << result;
throw std::runtime_error(oss.str());
convert it first to a string representation:
throw std::runtime_error(std::string("we did ") +
boost::lexical_cast(a_uint) +
" and got " +
boost::lexical_cast(result));
You might reasonably wonder why C++ doesn't provide operator+(std::string&, X&) for X in { short, int, long, long long, float, double, unsigned short etc. }, or even:
template <typename T>
std::string operator+(std::string& s, T& t)
{
std::ostringstream oss;
oss << t;
return s + oss.str();
}
In many cases it would be convenient. But streams are more powerful as you can tune the padding width and character, floating point precision etc.. Further, char is the 8-bit integer type, so how could the compiler know whether to append a single character with that ASCII value (e.g. 'A' for 65), or an ASCII representation of the numeric ASCII value "65"? (Currently it doesn't handle any ints, so treating it as a single ASCII char isn't confusing). Or should it work for >=16 bit numbers but not 8? That would make it impossible to resize variables to/from 8-bit ints without having to do a complex impact analysis to see which string operations needed to be rewritten. It's also good practice to minimise dependencies: some small but perhaps significant percentage of translation units using string may not currently have to include (and hence spend time parsing) (and hence ostream etc), and in general cyclic dependencies are a "code smell" and frustrate testability (string depends on ostringstream depends on string...).
Next time please post the full error (it should continue "with [ _Elem = ], could be one of [list of ambiguous overloads]").
The problem is that you concatenate UINT with a std::string. This is not a valid operation, you first have to convert the UINT to a std::string (search Google for handy functions). The compiler is trying to do its best and tries to match some of the std::string operators to the UINT. Apparently, it finds some matches but these certainly aren't what you are looking for.
Related
I want to convert a double value into a std::string. Currently I'm writing
return std::to_string(double_value);
But this only returns 7 digits because internally to_string() just uses std::vsnprintf with a %f format specifier (see also here).
I could now just call std::vsnprintf manually with %.15f as format specifier but this leads to trailing zeros.
My (in my eyes very obvious) goal now is to have an approach like this:
string o1 = to_string(3.14)
string o2 = to_string(3.1415926536)
assert(o1 == "3.14")
assert(o2 == "3.1415926536")
Here is a nice elaboration on trimming trailing zeros from the %.20 output but this answer is about 8 years old.
Maybe things have changed? Can I convert a double with double precision without trailing zeros in C++ today?
Solution:
Based on 2mans answer you can write a generic function like this:
template<typename T>
inline std::string tostr(T value) {
std::ostringstream s;
s.precision(std::numeric_limits<T>::digits10);
s << value;
return s.str();
}
which will behaves like desired for numeric types. Note that I took digits10 rather than max_digits10 to favor a nice decimal representation rather than more digits and trailing ..0000001
Also IMHO it's worth to add that [v][s][n]printf() together with the format string "%.15g" (rather than 'f') will also trim trailing zeros (won't work with more digits because they could not be represented with 64bit which would lead to things like a trailing '1', e.g. 3.12 -> "3.1200000000000001")
Still strange:
Maybe someone can tell me why std::to_string(double) which was introduced with C++-11 hard-codes to vsnprintf(..., "%f", ...) rather than so something like vsnprintf("%.15g") which would result in a more precise representation without affecting C code?
You can use string stream (sstring) with stream manipulators, see example below:
std::stringstream ss1;
std::stringstream ss2;
ss1.precision(15);
ss1 << 3.14;
std::cout << ss1.str()<<' '<<("3.14" == ss1.str())<<std::endl;
ss2.precision(15);
ss2 << 3.1415926536;
std::cout << ss2.str()<<' '<<("3.1415926536" == ss2.str())<<std::endl;
Or you can use boost format. Here's a link!
std::cout<<format("%.2f") % 3.14 <<std::endl;
std::cout<<format("%.10f") % 3.1415926536 <<std::endl;
tl:dr
How can I concatenate const char* with std::string, neatly and
elegantly, without multiple function calls. Ideally in one function
call and have the output be a const char*. Is this impossible, what
is an optimum solution?
Initial Problem
The biggest barrier I have experienced with C++ so far is how it handles strings. In my opinion, of all the widely used languages, it handles strings the most poorly. I've seen other questions similar to this that either have an answer saying "use std::string" or simply point out that one of the options is going to be best for your situation.
However this is useless advice when trying to use strings dynamically like how they are used in other languages. I cannot guaranty to always be able to use std::string and for the times when I have to use const char* I hit the obvious wall of "it's constant, you can't concatenate it".
Every solution to any string manipulation problem I've seen in C++ requires repetitive multiple lines of code that only work well for that format of string.
I want to be able to concatenate any set of characters with the + symbol or make use of a simple format() function just how I can in C# or Python. Why is there no easy option?
Current Situation
Standard Output
I'm writing a DLL and so far I've been output text to cout via the << operator. Everything has been going fine so far using simple char arrays in the form:
cout << "Hello world!"
Runtime Strings
Now it comes to the point where I want to construct a string at runtime and store it with a class, this class will hold a string that reports on some errors so that they can be picked up by other classes and maybe sent to cout later, the string will be set by the function SetReport(const char* report). So I really don't want to use more than one line for this so I go ahead and write something like:
SetReport("Failure in " + __FUNCTION__ + ": foobar was " + foobar + "\n"); // __FUNCTION__ gets the name of the current function, foobar is some variable
Immediately of course I get:
expression must have integral or unscoped enum type and...
'+': cannot add two pointers
Ugly Strings
Right. So I'm trying to add two or more const char*s together and this just isn't an option. So I find that the main suggestion here is to use std::string, sort of weird that typing "Hello world!" doesn't just give you one of those in the first place but let's give it a go:
SetReport(std::string("Failure in ") + std::string(__FUNCTION__) + std::string(": foobar was ") + std::to_string(foobar) + std::string("\n"));
Brilliant! It works! But look how ugly that is!! That's some of the ugliest code I've every seen. We can simplify to this:
SetReport(std::string("Failure in ") + __FUNCTION__ + ": foobar was " + std::to_string(foobar) + "\n");
Still possibly the worst way I've every encounter of getting to a simple one line string concatenation but everything should be fine now right?
Convert Back To Constant
Well no, if you're working on a DLL, something that I tend to do a lot because I like to unit test so I need my C++ code to be imported by the unit test library, you will find that when you try to set that report string to a member variable of a class as a std::string the compiler throws a warning saying:
warning C4251: class 'std::basic_string<_Elem,_Traits,_Alloc>' needs to have dll-interface to be used by clients of class'
The only real solution to this problem that I've found other than "ignore the warning"(bad practice!) is to use const char* for the member variable rather than std::string but this is not really a solution, because now you have to convert your ugly concatenated (but dynamic) string back to the const char array you need. But you can't just tag .c_str() on the end (even though why would you want to because this concatenation is becoming more ridiculous by the second?) you have to make sure that std::string doesn't clean up your newly constructed string and leave you with garbage. So you have to do this inside the function that receives the string:
const std::string constString = (input);
m_constChar = constString.c_str();
Which is insane. Because now I traipsed across several different types of string, made my code ugly, added more lines than should need and all just to stick some characters together. Why is this so hard?
Solution?
So what's the solution? I feel that I should be able to make a function that concatenates const char*s together but also handle other object types such as std::string, int or double, I feel strongly that this should be capable in one line, and yet I'm unable to find any examples of it being achieved. Should I be working with char* rather than the constant variant, even though I've read that you should never change the value of char* so how would this help?
Are there any experienced C++ programmers who have resolved this issue and are now comfortable with C++ strings, what is your solution? Is there no solution? Is it impossible?
The standard way to build a string, formatting non-string types as strings, is a string stream
#include <sstream>
std::ostringstream ss;
ss << "Failure in " << __FUNCTION__ << ": foobar was " << foobar << "\n";
SetReport(ss.str());
If you do this often, you could write a variadic template to do that:
template <typename... Ts> std::string str(Ts&&...);
SetReport(str("Failure in ", __FUNCTION__, ": foobar was ", foobar, '\n'));
The implementation is left as an exercise for the reader.
In this particular case, string literals (including __FUNCTION__) can be concatenated by simply writing one after the other; and, assuming foobar is a std::string, that can be concatenated with string literals using +:
SetReport("Failure in " __FUNCTION__ ": foobar was " + foobar + "\n");
If foobar is a numeric type, you could use std::to_string(foobar) to convert it.
Plain string literals (e.g. "abc" and __FUNCTION__) and char const* do not support concatenation. These are just plain C-style char const[] and char const*.
Solutions are to use some string formatting facilities or libraries, such as:
std::string and concatenation using +. May involve too many unnecessary allocations, unless operator+ employs expression templates.
std::snprintf. This one does not allocate buffers for you and not type safe, so people end up creating wrappers for it.
std::stringstream. Ubiquitous and standard but its syntax is at best awkward.
boost::format. Type safe but reportedly slow.
cppformat. Reportedly modern and fast.
One of the simplest solution is to use an C++ empty string. Here I declare empty string variable named _ and used it in front of string concatenation. Make sure you always put it in the front.
#include <cstdio>
#include <string>
using namespace std;
string _ = "";
int main() {
char s[] = "chararray";
string result =
_ + "function name = [" + __FUNCTION__ + "] "
"and s is [" + s + "]\n";
printf( "%s", result.c_str() );
return 0;
}
Output:
function name = [main] and s is [chararray]
Regarding __FUNCTION__, I found that in Visual C++ it is a macro while in GCC it is a variable, so SetReport("Failure in " __FUNCTION__ "; foobar was " + foobar + "\n"); will only work on Visual C++. See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx and https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
The solution using empty string variable above should work on both Visual C++ and GCC.
My Solution
I've continued to experiment with different things and I've got a solution which combines tivn's answer that involves making an empty string to help concatenate long std::string and character arrays together and a function of my own which allows single line copying of that std::string to a const char* which is safe to use when the string object leaves scope.
I would have used Mike Seymour's variadic templates but they don't seem to be supported by the Visual Studio 2012 I'm running and I need this solution to be very general so I can't rely on them.
Here is my solution:
Strings.h
#ifndef _STRINGS_H_
#define _STRINGS_H_
#include <string>
// tivn's empty string in the header file
extern const std::string _;
// My own version of .c_str() which produces a copy of the contents of the string input
const char* ToCString(std::string input);
#endif
Strings.cpp
#include "Strings.h"
const std::string str = "";
const char* ToCString(std::string input)
{
char* result = new char[input.length()+1];
strcpy_s(result, input.length()+1, input.c_str());
return result;
}
Usage
m_someMemberConstChar = ToCString(_ + "Hello, world! " + someDynamicValue);
I think this is pretty neat and works in most cases. Thank you everyone for helping me with this.
As of C++20, fmtlib has made its way into the ISO standard but, even on older iterations, you can still download and use it.
It gives similar capabilities as Python's str.format()(a), and your "ugly strings" example then becomes a relatively simple:
#include <fmt/format.h>
// Later on, where code is allowed (inside a function for example) ...
SetReport(fmt::format("Failure in {}: foobar was {}\n", __FUNCTION__, foobar));
It's much like the printf() family but with extensibility and type safety built in.
(a) But, unfortunately, not its string interpolation feature (use of f-strings), which has the added advantage of putting the expressions in the string at the place where they're output, something like:
set_report(f"Failure in {__FUNCTION__}: foobar was {foobar}\n");
If fmtlib ever got that capability, I'd probably wet my pants in excitement :-)
What's the purpose of boost::to_string (found in boost/exception/to_string.hpp) and how does it differ from boost::lexical_cast<std::string> and std::to_string?
std::to_string, available since C++11, works on fundamental numeric types specifically. It also has a std::to_wstring variant.
It is designed to produce the same results that sprintf would.
You may choose this form to avoid dependencies on external libraries/headers.
The throw-on-failure function boost::lexical_cast<std::string> and its non-throwing cousin boost::conversion::try_lexical_convert work on any type that can be inserted into a std::ostream, including types from other libraries or your own code.
Optimized specializations exist for common types, with the generic form resembling:
template< typename OutType, typename InType >
OutType lexical_cast( const InType & input )
{
// Insert parameter to an iostream
std::stringstream temp_stream;
temp_stream << input;
// Extract output type from the same iostream
OutType output;
temp_stream >> output;
return output;
}
You may choose this form to leverage greater flexibility of input types in generic functions, or to produce a std::string from a type that you know isn't a fundamental numeric type.
boost::to_string isn't directly documented, and seems to be for internal use primarily. Its functionality behaves like lexical_cast<std::string>, not std::to_string.
There are more differences: boost::lexical_cast works a bit different when converting double to string. Please consider the following code:
#include <limits>
#include <iostream>
#include "boost/lexical_cast.hpp"
int main()
{
double maxDouble = std::numeric_limits<double>::max();
std::string str(std::to_string(maxDouble));
std::cout << "std::to_string(" << maxDouble << ") == " << str << std::endl;
std::cout << "boost::lexical_cast<std::string>(" << maxDouble << ") == "
<< boost::lexical_cast<std::string>(maxDouble) << std::endl;
return 0;
}
Results
$ ./to_string
std::to_string(1.79769e+308) == 179769313486231570814527423731704356798070600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000
boost::lexical_cast<std::string>(1.79769e+308) == 1.7976931348623157e+308
As you can see, the boost version uses exponential notation (1.7976931348623157e+308) whereas std::to_string prints every digit, and six decimal places. One may be more useful than another for your purposes. I personally find the boost version more readable.
Here is a benchmark that I found for the integer to string conversion, hope it doesn't change much for float and double Fast integer to string conversion benchmark in C++.
I have a string containing hexadecimal values (two characters representing a byte). I would like to use std::stringstream to make the conversion as painless as possible, so I came up with the following code:
std::string a_hex_number = "e3";
{
unsigned char x;
std::stringstream ss;
ss << std::hex << a_hex_number;
ss >> x;
std::cout << x << std::endl;
}
To my biggest surprise this prints out "e" ... Of course I don't give up so easily, and I modify the code to be:
{
unsigned short y;
std::stringstream ss;
ss << std::hex << a_hex_number;
ss >> y;
std::cout << y << std::endl;
}
This, as expected, prints out 227 ...
I looked at http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ and http://www.cplusplus.com/reference/ios/hex/ but I just could not find a reference which tells me more about why this behaviour comes ...(yes, I feel that it is right because when extracting a character it should take one character, but I am a little bit confused that std:hex is ignored for characters). Is there a mention about this situation somewhere?
(http://ideone.com/YHt7Fz)
Edit I am specifically interested if this behaviour is mentioned in any of the STL standards.
If I understand correctly, you're trying to convert a string in
hex to an unsigned char. So for starters, since this is
"input", you should be using std::istringstream:
std::istringstream ss( a_hex_number );
ss >> std::hex >> variable;
Beyond that, you want the input to parse the string as an
integral value. Streams do not consider character types as
numeric values; they read a single character into them (after
skipping leading white space). To get a numeric value, you
should input to an int, and then convert that to unsigned
char. Characters don't have a base, so std::hex is
irrelevant for them. (The same thing holds for strings, for
example, and even for floating point.)
With regards to the page you site: the page doesn't mention
inputting into a character type (strangely enough, because it
does talk about all other types, including some very special
cases). The documentation for the std::hex manipulator is
also weak: in the running text, it only says that "extracted
values are also expected to be in hexadecimal base", which isn't
really correct; in the table, however, it clearly talks about
"integral values". In the standard, this is documented in
ยง27.7.2.2.3. (The >> operators for character types are not
member functions, but free functions, so are defined in
a different section.) What we are missing, however, is a good
document which synthesizes these sort of things: whether the
>> operator is a member or a free function doesn't really
affect the user much; you want to see all of the >> available,
with their semantics, in one place.
Let's put it simple: variable type is 'stronger' than 'hex'. That's why 'hex' is ignored for 'char' variable.
Longer story:
'Hex' modifies internal state of stringstream object telling it how to treat subsequent operations on integers. However, this does not apply to chars.
When you print out a character (i.e. unsigned char), it's printed as a character, not as a number.
Given an compile-time constant integer (an object, not a macro), can I combine it with a string literal at compile time, possibly with the preprocessor?
For example, I can concatenate string literals just by placing them adjacent to each other:
bool do_stuff(std::string s);
//...
do_stuff("This error code is ridiculously long so I am going to split it onto "
"two lines!");
Great! But what if I add integer constants in the mix:
const unsigned int BAD_EOF = 1;
const unsigned int BAD_FORMAT = 2;
const unsigned int FILE_END = 3;
Is it possible to use the preprocessor to somehow concatenate this with the string literals?
do_stuff("My error code is #" BAD_EOF "! I encountered an unexpected EOF!\n"
"This error code is ridiculously long so I am going to split it onto "
"three lines!");
If that isn't possible, could I mix constant strings with string literals? I.e. if my error codes were strings, instead of unsigneds?
And if neither is possible, what is the shortest, cleanest way to patch together this mix of string literals and numeric error codes?
If BAD_EOF was a macro, you could stringize it:
#define STRINGIZE_DETAIL_(v) #v
#define STRINGIZE(v) STRINGIZE_DETAIL_(v)
"My error code is #" STRINGIZE(BAD_EOF) "!"
But it's not (and that's just about always a good thing), so you need to format the string:
stringf("My error code is #%d!", BAD_EOF)
stringstream ss; ss << "My error code is #" << BAD_EOF << "!";
ss.str()
If this was a huge concern for you (it shouldn't be, definitely not at first), use a separate, specialized string for each constant:
unsigned const BAD_EOF = 1;
#define BAD_EOF_STR "1"
This has all the drawbacks of a macro plus more to screwup maintain for a tiny bit of performance that likely won't matter for most apps. However, if you decide on this trade-off, it has to be a macro because the preprocessor can't access values, even if they're const.
What's wrong with:
do_stuff(my_int_1,
my_int_2,
"My error code is #1 ! I encountered an unexpected EOF!\n"
"This error code is ridiculously long so I am going to split it onto "
"three lines!");
If you want to abstract the error codes, then you can do this:
#define BAD_EOF "1"
Then you can use BAD_EOF as if it were a string literal.