Is there an easy way to combine strings as function parameter? - c++

Let's say I have a C++ function
void foo(std::string str) {
std::cout << str << "\n";
}
Now, in the equivalent Java I could call the function with a combination of various types and it would automatically be concatenated, for example:
foo("test " + intValue + " " + stringValue + "...");
This does not work in C++, but is there a way in modern C++ to achieve the same? The only solution I have found is to create a stringstream variable and do the concatenation there. However, that seems like a lot of overhead for such a common use case.

You can wrap std::stringstream in a function and use that:
#include <string>
#include <sstream>
void foo(std::string){}
template<typename...Args>
std::string concat(Args&&...args){
std::stringstream ss;
(ss << ... << args);
return ss.str();
}
int main(){
int intValue=12;
std::string stringValue="hello";
foo(concat("test ",intValue," ",stringValue,"..."));
}
std::string supports concatenation by +, but primitives types do not. So, you can wrap them in std::to_string but that is not so nice.
Allowing "hello"+5 is too dangerous because "hello" is one easy step from being const char* which would trigger pointer arithmetic instead.
From C++20, there is std::format.

You could create a string builder class that wrapps the boilerplate of the std::stringstream a bit:
#include <iostream>
#include <string>
#include <sstream>
struct Builder {
std::stringstream s;
template<typename T>
Builder(const T& x) {
s << x;
}
template<typename T>
friend Builder&& operator+(Builder&& b, const T& val) {
b.s << val;
return std::move(b);
}
operator std::string() const {
return s.str();
}
};
Call site could use it like this:
foo(Builder("test ") + 3 + " " + "stringValue" + "...");
Live example here.

You can achieve the same by using to_string() on integer values.
foo("test " + to_string(intValue) + " " + stringValue + "...");

Related

Log anything i want using auto keyword

I programmed a log class that logs messages in color in the terminal. I want it to be able to log anything
I give it to log. I guess templates are the way to go. But can't i use auto as an argument type, then check if it is a string and if not call the tostring method of the object ?
Since c++20 you can use auto and overload for the other types you want to handle differently.
void log(auto test) {
std::cout << std::to_string(test) << std::endl;
}
void log(const std::string &str) {
std::cout << "str: " << str << std::endl;
}
int main()
{
log(std::string("test"));
log(10);
}
You could indeed use templates, then just add a template specialization for std::string that doesn't invoke std::to_string
#include <iostream>
#include <string>
template <typename T>
void ToLog(T t)
{
std::cout << std::to_string(t) << '\n';
}
template <>
void ToLog<std::string>(std::string str)
{
std::cout << str << '\n';
}
int main()
{
ToLog(5);
ToLog(12.0);
ToLog(std::string("hello"));
return 0;
}
Output
5
12.000000
hello
No, auto needs to determine the type of a variable in compile time, which can't be done until C++20. If you are using C++ standard, either you use templates, preprocessor macros (as some logging libraries do) or directly some to_string function before passing the argument.
But, as said, with C++20 it can be done, and behaves like a template.
You might find this question useful.

Why does a std::string object passed to a template function not prefer std::string overload?

I'm writing a program and I want to be able to cleanly wrap a string in quotes without having to do something like
std::string firstString = "This is a string";
std::string myString = "\"" + firstString + "\"";
So I wrote a couple of template functions to take their arguments and wrap them in quotes. I've also included my first (naive) attempt at writing a general toString() function (I know about to_string, but I'm doing this for learning too).
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <typeinfo>
template <typename T>
std::string toString(const T &convert)
{
std::string returnString{""};
std::stringstream transfer;
transfer << convert;
transfer >> returnString;
return returnString;
}
template<typename T>
std::string tQuoted(const T &convert)
{
std::cout << "Called template overload" << std::endl;
return ("\"" + toString(convert) + "\"");
}
template<typename T>
std::string tQuoted(const std::string &convert)
{
std::cout << "Called std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
template<typename T>
std::string tQuoted(const char *convert)
{
std::cout << "Called const char overload" << std::endl;
return ("\"" + static_cast<std::string>(convert) + "\"");
}
template<typename T>
std::string tQuoted(std::string convert)
{
std::cout << "Called normal std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
template<typename T>
std::string tQuoted(std::string&& convert)
{
std::cout << "Called rvalue std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
int main()
{
std::vector<std::string> my{"Hello", "30 Days Of Coding", "All Work And No Play"};
std::string myString = "Hello, World!";
std::string *strPtr = &myString;
std::string *mySuperPtr = new std::string{"He's a cockaroach"};
for (std::vector<std::string>::const_iterator iter = my.begin(); iter != my.end(); iter++) {
std::cout << tQuoted(*iter) << std::endl;
}
std::cout << tQuoted(myString) << std::endl;
std::cout << tQuoted(*strPtr) << std::endl;
std::cout << tQuoted(mySuperPtr) << std::endl;
std::cout << tQuoted(std::string{"Another string"}) << std::endl;
delete mySuperPtr;
mySuperPtr = nullptr;
return 0;
}
Every one of those calls the template constructor:
Called template overload
"Hello"
Called template overload
"30"
Called template overload
"All"
Called template overload
"Hello,"
Called template overload
"Hello,"
Called template overload
"0x13cad10"
Called template overload
"Another"
Of course, a much less naive toString() method would do basic checking to see if the parameter was a std::string, and just return that if it was. It seems that a std::stringstream will stop when it encounters the first space in a string (hence the truncated output). However, this isn't the main focus of my confusion.
Sorry for the very basic question, but this one really has me stumped. Thanks for any help you can provide.
You are not specializing the template function correctly. This is how to correctly specialize it:
template<>
std::string tQuoted(const std::string &convert)
{
std::cout << "Called std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
Resulting output becomes:
Called std::string overload
"Hello"
Called std::string overload
"30 Days Of Coding"
Called std::string overload
"All Work And No Play"
Called std::string overload
"Hello, World!"
Called std::string overload
"Hello, World!"
Called template overload
"0x1c27d10"
Called std::string overload
"Another string"
Note that for
tQuoted(mySuperPtr)
mySuperPtr is a pointer to a string, and not a string, hence this doesn't use the specialized template function.
Take a careful look at this function template that you wrote:
template<typename T>
std::string tQuoted(const std::string &convert)
{
std::cout << "Called std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
It's a function template, with template parameter T, but where does T come from? It's nowhere. Specifically, it's a non-deduced context. There's no way for the compiler to tell what T is from tQuoted(myString), you'd have to explicitly call tQuoted<X>(myString).
But in this case, you don't actually want T anyway. You're not trying to write a new function template. You're trying to write an overload specifically for std::string (as the body of your function suggests). So just write an overload:
std::string tQuoted(const std::string &convert)
{
std::cout << "Called std::string overload" << std::endl;
return ("\"" + convert + "\"");
}
No template necessary. The same is true of all your other overloads - they are all accidentally function templates with template parameters that are non-deduced contexts.
Avoid function template specializations unless you really, really need them. Which, in this case, you don't. See Why Not Specialize Function Templates?

C++ declare a string literal in mutable memory

I am working on a challenge given to me by a friend and to complete it I need to pass a mutable string into a function without prior declaration. (The function preforms some operations on the string so it must be mutable and due to constraints in the challenge I cannot declare the variable before the function call. Basically can
myFunction("abcdef");
be altered in such a way that the string is declared in the function call and passed or so that the passed string is not declared in non-mutable memory.
Here is a version which changes the call to be
myFunction("abcdef"_ncs);
I guess, this innocent addition for "non-const string" should be permissible. Here is the code:
#include <cstring>
#include <cstddef>
#include <iostream>
void myFunction(char* x) {
std::cout << "x=" << x << "\n";
}
struct tmp_string {
char* buffer;
tmp_string(char const* str, std::size_t n)
: buffer(std::strcpy(new char[n + 1], str)) {
}
tmp_string(tmp_string&& other): buffer(other.buffer) { other.buffer = 0; }
~tmp_string() { delete[] buffer; }
operator char*() { return buffer; }
};
tmp_string operator"" _ncs(char const* str, std::size_t n) {
return tmp_string(str, n);
}
int main()
{
myFunction("abcdef"_ncs);
}
I didn't use std::string primarily because there is no neat conversion from a std::string to a non-const string. The only approach I could think of would be
myFunction(&std::string("abcdef")[0]);
At least, it would also neatly clean up after itself (as does the approach using tmp_string above). Note that starting with C++11 the approach taking the address of the first byte also yields a null-terminated string (for C++03 the string wasn't guaranteed to be null-terminated; since I had trouble verifying this guarantee: it is in 21.4.5 [string.access] paragraph 2).
Here is a simple way to do this.
#include <iostream>
using namespace std;
void MyFunc(char* c)
{
c[0] = 's';
cout << c << endl;
delete[] c;
}
int main()
{
MyFunc(new char[3]{'a','b', 0});
return 0;
}

Turning temporary stringstream to c_str() in single statement

Consider the following function:
void f(const char* str);
Suppose I want to generate a string using stringstream and pass it to this function. If I want to do it in one statement, I might try:
f((std::ostringstream() << "Value: " << 5).str().c_str()); // error
This gives an error: 'str()' is not a member of 'basic_ostream'. OK, so operator<< is returning ostream instead of ostringstream - how about casting it back to an ostringstream?
1) Is this cast safe?
f(static_cast<std::ostringstream&>(std::ostringstream() << "Value: " << 5).str().c_str()); // incorrect output
Now with this, it turns out for the operator<<("Value: ") call, it's actually calling ostream's operator<<(void*) and printing a hex address. This is wrong, I want the text.
2) Why does operator<< on the temporary std::ostringstream() call the ostream operator? Surely the temporary has a type of 'ostringstream' not 'ostream'?
I can cast the temporary to force the correct operator call too!
f(static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << "Value: " << 5).str().c_str());
This appears to work and passes "Value: 5" to f().
3) Am I relying on undefined behavior now? The casts look unusual.
I'm aware the best alternative is something like this:
std::ostringstream ss;
ss << "Value: " << 5;
f(ss.str().c_str());
...but I'm interested in the behavior of doing it in one line. Suppose someone wanted to make a (dubious) macro:
#define make_temporary_cstr(x) (static_cast<std::ostringstream&>(static_cast<std::ostringstream&>(std::ostringstream()) << x).str().c_str())
// ...
f(make_temporary_cstr("Value: " << 5));
Would this function as expected?
You cannot cast the temporary stream to std::ostringstream&. It is ill-formed (the compiler must tell you that it is wrong). The following can do it, though:
f(static_cast<std::ostringstream&>(
std::ostringstream().seekp(0) << "Value: " << 5).str().c_str());
That of course is ugly. But it shows how it can work. seekp is a member function returning a std::ostream&. Would probably better to write this generally
template<typename T>
struct lval { T t; T &getlval() { return t; } };
f(static_cast<std::ostringstream&>(
lval<std::ostringstream>().getlval() << "Value: " << 5).str().c_str());
The reason that without anything it takes the void*, is because that operator<< is a member-function. The operator<< that takes a char const* is not.
A temporary cannot be passed as a non-const reference to a function, that's why it does not find the correct streaming operator and instead takes the one with void* argument (it is a member function and thus calling it on a temporary is OK).
What comes to getting around the limitations by casting, I have a feeling that it is in fact UB, but I cannot say for sure. Someone else will surely quote the standard.
This can be done using a C++11 lambda function.
#include <iostream>
#include <sstream>
void f(const char * str)
{
std::cout << str << std::endl;
}
std::string str(void (*populate)(std::ostream &))
{
std::ostringstream stream;
populate(stream);
return stream.str();
}
int main(int argc, char * * args)
{
f(str([](std::ostream & ss){ ss << "Value: " << 5; }).c_str());
return 0;
}
// g++ -std=c++11 main.cpp -o main
// ./main
// Value: 5
If you like one_lined statements you can write:
// void f(const char* str);
f(static_cast<ostringstream*>(&(ostringstream() << "Value: " << 5))->str());
However you should prefer easier to maintain code as:
template <typename V>
string NumberValue(V val)
{
ostringstream ss;
ss << "Value: " << val;
return ss.str();
}
f(NumberValue(5));
I use something a bit like this for logging.
#include <sstream>
using namespace std;
const char *log_text(ostringstream &os, ostream &theSame)
{
static string ret; // Static so it persists after the call
ret = os.str();
os.str(""); // Truncate so I can re-use the stream
return ret.c_str();
}
int main(int argc, char **argv)
{
ostringstream ss;
cout << log_text(ss, ss << "My first message") << endl;
cout << log_text(ss, ss << "Another message") << endl;
}
Output:
My first message
Another message
Since C++17 we have folding expressions for templates that can be used to make generic string formatter that can accept everything that have stream support:
template <class... Args>
std::string format(Args &&... args)
{
std::ostringstream ostr;
(ostr << ... << args);
return ostr.str();
}
The you can use it like: format("Int number: ", 42, " Float number: ", 3.14).c_str().
In C++20 std::format is coming.

std::string and format string

I found the below code through Google. It almost does what I want it to do, except it doesn't provide a way to indicate the precision like '%.*f' does in C-type format strings. Also, it doesn't provide anything further than 5 decimal places. Am I going to have to stick with C strings and snprintf?
#include <string>
#include <sstream>
#include <iostream>
template <class T>
std::string to_string(T t, std::ios_base & (*f)(std::ios_base&))
{
std::ostringstream oss;
oss << f << t;
return oss.str();
}
int main()
{
std::cout<<to_string<double>(3.1415926535897931, std::dec)<<std::endl;
return 0;
}
You want to use the std::setprecision manipulator:
int main()
{
std::cout << std::setprecision(9) << to_string<long>(3.1415926535897931, std::dec)
<< '\n';
return 0;
}
C++ wouldn't be successful if it couldn't do something C could.
You need to check out manipulators.
If you want C-style formatting (which I do prefer, it's more terse), check out Boost.Format.
Have you looked at Boost::format?
Edit: It's not entirely clear what you want. If you just want to write to a string, with formatting, you can use normal manipulators on a stringstream. If you want to use printf-style formatting strings, but retain type-safety, Boost::format can/will do that.
Taking the almost-correct answer (note that std::dec is redundant in this simple case):
int main()
{
std::cout << std::setprecision(9) << std::dec << 3.1415926535897931 << std::endl;
return 0;
}
However, if you wanted the to_string function to behave as desired, that's a bit more difficult. You'd need to pass setprecision(9) to the to_string<T> function, and it doesn't accept arguments of that type. You'd want a templated version:
template <class T, class F>
std::string to_string(T t, F f)
{
std::ostringstream oss;
oss << f << t;
return oss.str();
}
int main()
{
std::cout << to_string<double>(3.1415926535897931, std::setprecision(9)) << std::endl;
return 0;
}
This works because you really didn't need std::dec in to_string. But if you needed to pass more manipulators, the simple solution is to add template <class T, class F1, class F2> std::string to_string(T t, F1 f1, F2 f2) etcetera. Technically this doesn't scale very well, but it's going to be so rare that you probably don't need it at all.