std::string not updated with = operator - c++

So here's a puzzle for some C++ developers here.
I have a custom String class I'm working with that's supposed to teach me how to get comfortable with classes and a few other C++ features and this class has a value property it uses to keep track of its primitive value (which is a std::string).
But here's a problem, I have define multiple methods for creating an object of this class. 2 of which I understand perfectly:
String stringA = "Hello, World!";
String stringB = String("Hello, World!");
But the last one is a bit tricky as it should be able to work with an infinite set of arguments (theoretically).
String stringC = String("Hello,", ' ', "World!");
But when I access the primitive values of these strings, the last one seems to bug out and return (to the best of my debugging efforts) nothing, garbled text or just part of the arguments given.
stringA.valueOf(); // -> Hello, World!
stringB.valueOf(); // -> Hello, World!
stringC.valueOf(); // -> Hello,
Now, this has been a challenge I've really struggled with especially as a JavaScript developer diving into C++. I know the two languages are fundamentally different, but I figure that logically there should be some features of the former that can somewhat be applied to the latter (such as variadic arguments).
For anyone who can help with this and explain to me what I'm missing (or why my code sucks), you're an absolute champ. Great going for you.
#include <iostream>
/* Let's assume there's a `stringify` function that converts any value to `std::string` */
class String {
private:
std::string value;
public:
template <typename data>
String(data arg) { this -> value += arg; }
template <typename data, typename... argumentsData>
String(data arg, argumentsData... args) {
this -> value += arg;
String(args...);
}
template <typename data>
String operator =(data arg) { return String(this -> value = arg); }
std::string valueOf() const { return this -> value; }
};
int main() {
String stringA = "Hello, World!";
String stringB = String("Hello, World!");
String stringC = String("Hello,", ' ', "World!");
std::cout << "String A: " << stringA.valueOf() << std::endl;
std::cout << "String B: " << stringB.valueOf() << std::endl;
std::cout << "String C: " << stringC.valueOf() << std::endl;
return 0;
}

In your constructor
template <typename data, typename... argumentsData>
String(data arg, argumentsData... args) {
this -> value += arg;
String(args...);
}
This line: String(args...); creates and discards a temporary String, which doesn't affect the state of the original object.
Instead of trying to solve this with recursion, I recommend using fold expressions:
template <typename ...P>
String(const P &... params) // Passing by const reference is purely an optimization.
{
((value += params) , ...);
}

Related

How to use some type specific function (such as .size() for std::string or std::vector and so on) on something of template type?

If possible, how could I use some type-specific function (such as .size() for: std::string or std::vector or ...) in a function with a template type, being sure that when I'll use that type-specific function I'm actually calling it with the correct type as argument? Maybe I'm wrong, and if it is, please explain to me what I have to do.
#include <iostream>
#include <string>
template <typename T>
std::string func(T& number) {
if (typeid(T) == typeid(std::string)) {
unsigned short int size = number.size();// !
return " is a string";
}
else if (typeid(T) == typeid(int)) {
return " is an int";
}
//...
}
int main() {
std::string name = "Anthony";
int age = 8;
std::cout << name /*<< func(name) */<< '\n' << age << func(age) << '.';
return 0;
}
I know that in the code above the line:
unsigned short int size = number.size();//(I need exactly '.size()')
doesn't make any sense (even the whole code doesn't make much sense) considering that I never use that value, but to find the size of the string (when it is a string!) is exactly what I need, and to not post a very long code that would make sense, I'm posting only this to make it give the error I've had when trying to compile, and in order to give you a minimal reproducible example. So please, don't say to me "just delete that line and your code will work").
Instead of if (typeid(T) == typeid(std::string)), use if constexpr (std::is_same_v<T, std::string>). ( Similarly, else if constexpr instead of else if).
Regular if requires both branches to be valid, even if the condition is known at compile-time. if constexpr requires a compile-time condition, but allows the discarded branch to be invalid (only if the error is related to the template argument; every branch has to be theoretically valid for some template argument).
std::is_same_v<T, std::string> is similar to typeid(T) == typeid(std::string), except it counts as a compile-time constant. if constexpr would reject the latter.
If you really need to use a template here, simply specialize the template.
template <typename T>
std::string func(T& number);
template<>
std::string func<std::string>(std::string& number) {
unsigned short int size = number.size();// !
return " is a string";
}
template<>
std::string func<int>(int& number) {
return " is an int";;
}
Usually you using a template you want to avoid using specific implementations for types though. Overloads would be preferrable for a limited set of types using type-specific implementations though.
Since your requirement is not restricted to std::string(as you have mentioned std::vector etc), you can use SFINAE as shown below:
#include <iostream>
#include<typeinfo>
#include<string>
#include<vector>
#include <type_traits>
//make sure that this overload is added to the set when T has a size() member function which is your requirement
template<typename T>
auto func(T const& number) -> decltype((void)(number.size()), std::string())
{
auto size = number.size();
return " is a " + std::string(typeid(number).name());
}
template<typename T>
std::enable_if_t<std::is_fundamental_v<std::remove_reference_t<T>>,std::string> func(T const& number)
{
return " is a " + std::string(typeid(number).name());
}
int main()
{
std::string name = "Anthony";
int age = 8;
double dage = 22.2;
std::cout << name << func(name) << '\n' << age << func(age) << '.'<<"\n"<<dage << func(dage);
//lets test it with vector
std::vector<int> vec= {1,2,3};
std::cout<<"\nvec: "<< func(vec);
return 0;
}
Demo
The output of the above program can be seen here:
Anthony is a NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
8 is a i.
22.2 is a d
vec: is a St6vectorIiSaIiEE

High level print function for C++ [duplicate]

This question already has answers here:
How do I print out the arguments of a function using a variadic template?
(3 answers)
Closed 2 years ago.
Is there a way to create a function or a macro in C++ that you can use like Python?
What i mean is a function like:
print(i); // i is an integer.
print(i, s); // i is an integer, s is a std::string. They are separated by a white space.
A function that takes in a number of arguments, then just prints them out regardless of the types.
Use streams:
std::cout << i << ' ' << s << '\n';
For more complex formatting consider fmt, it supports the syntax for python's str.format as well as printf style formatting (but typesafe).
If you are allowed to use C++17, you can do it using fold-expression, like this:
#include <iostream>
template<class ...Args>
void print(const Args &...args) {
auto seq_started = false;
auto print_impl = [&](auto &value) mutable {
if (seq_started) {
std::cout << " " << value;
} else {
seq_started = true;
std::cout << value;
}
};
(print_impl(args), ...);
}
int main() {
print("foo", 10, "bar", 20, "baz");
return 0;
}
I assume that the question is about general solution and that print is just an example.
The answer is: yes, with a combination of overloads and templates. First you setup functions per type:
void print_impl(const std::string& arg) {
std::cout << arg;
}
void print_impl(int arg) {
// Note: this is an example. Of course cout already
// does that for us with simple
// std::cout << arg;
print_impl(convert_to_string(arg));
}
// cout already has lots of overloads, we can take
// advantage of that if needed:
template<class TArg>
void print_impl(TArg&& arg) {
std::cout << std::forward<TArg>(arg);
}
then templates:
template<class TArg>
void print(TArg&& arg) {
print_impl(std::forward<TArg>(arg));
}
template<class TArg1, class ... TArgs>
void print(TArg1&& arg1, TArgs&& ... args) {
print_impl(std::forward<TArg1>(arg1)); // <-- print first argument
print_impl(" "); // <-- insert separator, requires const std::string& overload
print(std::forward<TArgs>(args)...); // <-- recursive call
}
In the code above you can replace calls to print_impl with calls to std::cout << operator directly, if needed. Although I would keep print_impl because it is a nice layer above std::cout in case you want to replace it in the future.
Then you can use it similar to Python:
int main()
{
print("test");
print(1, 2, "foo");
print("foo", 1, 2);
return 0;
}

Converting parameters when passing to functions (c++)

I am just starting to teach myself C++ and am having a hard time with function parameter passing. For example I am using my own print function where you simply put the string into the parameters and it logs it to the console.
//Print Function
void print(std::string message = "") {
std::cout << message << std::endl;
}
However because I declare it as a std::string variable if I pass it a number it will not print it. Ultimately I would like to make an input and print system like in Python. How to I go about this? Is there a way to convert the parameters to string? Or some other solution. Another function with similar problems is my input function:
//Input function (Enter does not work without text, space is not text)
std::string input(const char* message = "") {
std::cout << message;
std::string x;
std::cin >> x;
return x;
}
This does not allow the return to be an int witch makes calculations using the input harder. Any help is appreciated thanks in advance!
~ Moses
Besides template, if your compiler supports C++14, You can also use auto with lambda function. You can just write all these inside the main function.
auto print = [](const auto& message) {std::cout << message << std::endl;};
print(1); //1
print("AAA"); //AAA
Note that, unlike Python, when you want to print something, you don't need to convert it to a string first. As long as the thing you want to print has overloaded cout, You can simply cout it. And using template or auto doesn't change the fact that everything in C++ is statically typed, it's just that the compiler will create the different versions of overload functions for you automatically.
EDIT
As #Peter pointed out in the comment section, saying "cout is something that can be overloaded is flat-out wrong", and more accurate to say overloading the operator<< for the ostream and the corresponding class
Can++ templates are useful there.
//Print Function
template <typename T>
void print(const T& message) {
std::cout << message << std::endl;
}
void print() {
std::cout << std::endl;
}
Note, I removed a default argument value and used overloaded function. With passed empty argument type of template parameter can not be deduced. print does not work with containers and you need more efforts to print containers, in Python it works from box.
//Input function (Enter does not work without text, space is not text)
template <typename T>
T input(const char* message = "")
{
std::cout << message;
T x;
std::cin >> x;
return x;
}
Usage: int n = input<int>("Input number:");.
Alternatively I discovered a way to do this without using lambda:
void print(int message) {
std::cout << message << std::endl;
};
void print(float message) {
std::cout << message << std::endl;
};
void print(std::string message) {
std::cout << message << std::endl;
};
By making multiple functions with the same name it will use what ever one works, so any input (3.14, 8, "Hello") will all work and use corresponding function.

How to print input c++ function parameter values automatically

I was wondering if there is a macro or standard way (for debugging purposes) to automatically print the value of the parameters of a function f, just like __FUNCTION__ prints/shows the function signature? For example,
void foo(int x, string y) {
cout << __FUNCTIION_ARGS__ << endl;
}
should show the values of x, and y.
If there is no such magic the standard way, is it possible to write a macro/template to do this?
--Update--
Per #jxh's comment, if print inside the function in question is impossible with macro/templates, is it possible to do it automatically on the caller-side, with something like:
call(foo,x,y);
which prints every parameter value, and behaves the same with foo(x,y) as if it is called directly in every other aspect? If a value is not printable (e.g. pointers, functions), the wrapper call can just print an opaque value such as <ptr> or <noprint>.
Thanks
P.S. I am using gcc, (and also clang in the future).
My take on it :
#include <iostream>
// Dummy parameter-pack expander
template <class T>
void expand(std::initializer_list<T>) {}
// Fun
template <class Fun, class... Args>
typename std::result_of<Fun&&(Args&&...)>::type
call(Fun&& f, Args&&... args) {
// Print all parameters
std::cout << "Params : ";
expand({(std::cout << args << ' ', 0)...});
std::cout << '\n';
// Forward the call
return std::forward<Fun>(f)(std::forward<Args>(args)...);
}
// Random test function
int myFunc(std::string const &s, double d, int i) {
std::cout << s << ' ' << d << ' ' << i << '\n';
return 57;
}
int main()
{
// Painless call
std::cout << call(myFunc, "hello", 3.14, 42) << '\n';
return 0;
}
Output :
Params : hello 3.14 42
hello 3.14 42
57
Variadic templates are fun !
There is no macro for printing the arguments, but you can print the function prototype using the __PRETTY_FUNCTION__ macro

Simple command to combine an arbitrary number of values of arbitrary types into a single string

Consider the following code.
int id = 666;
stringstream stream(stringstream::in | stringstream::out);
stream << "Object " << id << " active.";
file.write(stream.str());
It combines all the values preceded by << in a string quite nicely. I would love to discover a shorter, easier to use version with less code duplication. Furthermore, the above code is just an example, and the command should accept arbitrary combinations of variables and strings. Ideally something like:
int id = 666;
WRITE("Object ", id, " active.");
Is this possible in C++ in a portable way, even with Boost.Preprocessor, inlined functions and all the bag of tricks.
You can accomplish this without type checking using a macro:
//filewrite.h
#define WRITE(first, second, third) \
{\
stringstream stream(stringstream::in | stringstream::out);\
stream << first << second << third;\
file.write(stream.str());\
}
Or, cleaner, with a template function:
template<typename T1, typename T2, typename T3>
void WRITE(T1 const& first, T2 const& second, T3 const& third, fstream& file)
{
stringstream stream(stringstream::in | stringstream::out);
stream << first << second << third;
file.write(stream.str());
}
If you really don't want type-checking don't use C++, it's a statically-typed language!
If you just mean you want it to work for any type, either use a macro (eurgh) or use variadic templates, something like https://gitlab.com/redistd/redistd/blob/master/include/redi/printers.h which supports:
#include <redi/printers.h>
using redi::println;
int main()
{
int id = 666;
println("Object ", id, " active."); // write arguments to stdout
}
The println function takes any number of arguments and was shamelessly stolen from inspired by some example code from Howard Hinnant.
It would be quite easy to adapt that to write to an fstream instead of std::cout e.g. by adding
inline
void
fprintln()
{ file << std::endl; }
template<typename T0, typename... T>
inline
void
fprintln(const T0& t0, const T&... t)
{
print_one(file, t0);
fprintln(t...);
}
Then:
fprintln("Object ", id, " active."); // write arguments to 'file'
You don't need (nor want) macros. This is what templates were designed
for:
template <typename T>
void
write( std::string const& prefix, T const& value, std::string const& suffix )
{
std::ostringstream fmt;
fmt << prefix << value << suffix;
file.write( fmt.str() );
}
On the other hand, why bother? Why not just let the client code use the
idiomatic:
file << prefix << value << suffix;