I started learning C++ and I made a simple thing like printing variables etc, but I wanted to make a new value on a variable like in Python:
test = "hello world"
print(test)
test = 5
print(test + 6)
So I had this:
string test = "hello world";
cout << test << "\n";
And now I wanted to assign a number to test, so I used int test = 5;, but I got an error:
redefinition of 'test' with a different type
Is it possible to assign a new type to a variable somehow?
is it possible to assign a new type to a variable somehow?
A new type, no. C++ is a statically typed language. Variable types are specified at compile-time and cannot change at runtime.
For what you are asking, the closest thing available is std::variant in C++17 and later, which is a fixed class type that can hold different kinds of values at runtime, eg:
#include <iostream>
#include <string>
#include <variant>
using myVariant = std::variant<int, std::string>;
void print(const myVariant &v)
{
std::visit([](const auto &x) { std::cout << x; }, v);
std::cout << "\n";
}
int main()
{
myVariant test;
test = "hello world";
print(test);
test = 5;
print(test);
return 0;
}
Online Demo
In C++17 and newer, std::variant is a type that can be used to store multiple different types of data. Though you'll have to do a bit of finagling with visitors to get the polymorphic print you know from Python.
#include <variant>
#include <string>
#include <iostream>
struct PrintVisitor {
template <typename T>
void operator()(const T& arg) {
std::cout << arg << std::endl;
}
};
int main() {
std::variant<std::string, int> test = "hello world";
std::visit(PrintVisitor(), test);
test = 5;
std::visit(PrintVisitor(), test);
}
Related
I'm new to C++ and very confused on how to approach this. In Javascript, I can do something like this to access an object dynamically very easily:
function someItem(prop) {
const item = {
prop1: 'hey',
prop2: 'hello'
};
return item[prop];
}
In C++, I'm assuming I have to use a Struct, but after that I'm stuck on how to access the struct member variables dynamically.
void SomeItem(Property Prop)
{
struct Item
{
Proper Prop1;
Proper Prop2;
};
// Item[Prop] ??
}
This could be terrible code but I'm very confused on how to approach this.
This is a simple example of how to create an instance of a struct and then access its members:
#include <iostream>
#include <string>
struct Item {
std::string prop1 = "hey";
std::string prop2 = "hello";
};
int main() {
Item myItem;
std::cout << myItem.prop1 << std::endl; // This prints "hey"
std::cout << myItem.prop2 << std::endl; // This prints "hello"
return 0;
}
As mentioned in the comments, it looks like you might want a map. A map has keys and values associated with them, as an example you could have a key "prop1" be associated with a value "hey":
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, std::string> myMap;
myMap["prop1"] = "hey";
myMap["prop2"] = "hello";
std::cout << myMap["prop1"] << std::endl; // This print "hey"
std::cout << myMap["prop2"] << std::endl; // This print "hello"
return 0;
}
The first would be considered "normal" struct usage in C++ and the other is more applicable to cases where you have to look things up by keys
As mentioned in a comment, in C++ you would not define a custom structure for this, but rather use a std::unordered_map. I don't know Javascript, though if Property is an enum (it could be something else with small modifications) and return item[prop]; is supposed to return a string, then this might be close:
#include <string>
#include <unordered_map>
#include <iostream>
enum class Property { prop1,prop2};
std::string someItem(Property p){
const std::unordered_map<Property,std::string> item{
{Property::prop1,"hey"},
{Property::prop2,"hello"}
};
auto it = item.find(p);
if (it == item.end()) throw "unknown prop";
return it->second;
}
int main(){
std::cout << someItem(Property::prop1);
}
std::unordered_map does have a operator[] that you could use like so return item[p];, but it inserts an element into the map when none is found for the given key. This is not always desirable, and not possible when the map is const.
Consider this example:
#include <vector>
#include <string>
#include <functional>
#include <iostream>
using closure_type = std::function<void(void)>;
using closure_vec = std::vector<closure_type>;
class callbacks {
static closure_type common(std::string name, uint32_t number) {
return [number, name]() { std::cout << name << number << std::endl; };
}
public:
static closure_type foo(uint32_t number) { return common("foo ", number); }
static closure_type print(std::string msg) {
return [msg]() { std::cout << "print " << msg << std::endl; };
}
};
template <typename... calls_t> closure_vec wrap(uint32_t number, calls_t &&... calls) {
return closure_vec {
callbacks::foo(number),
std::forward<calls_t>(calls)...,
};
}
int main() {
auto vec = wrap(42,
callbacks::print("hello, "),
callbacks::print("world"));
for(auto &e: vec)
e();
return 0;
}
Demo (On the right most tab there is a full message)
When this code is checked with clang-tidy, I get the following warning:
warning: Potential memory leak [clang-analyzer-cplusplus.NewDeleteLeaks]
The line number points at the scope exit of the wrap function.
As I understand the message, the tool is concerned that the results form callbacks::foo might be lost. But I don not understand how is it possible: std::function is a safe class and should destroy everything nicely in its destructor. Also its lifetime is controlled by the vector which is safe too.
What is going on here? How do I fix this or workaround?
Unfortunately I cannot just suppress the warning, as this code is scattered everywhere in the codebase.
Try
closure_vec retval;
retval.reserve(sizeof...(calls)+1);
retval.push_back(callbacks::foo(number));
( retval.push_back(std::forward<calls_t>(calls)), ... );
return retval;
this avoids the const initializer_list contained copies of std function your code created, so should be more efficient as well.
Live example.
I tried using a C style array here, but I got the warning as well despite not using a std::initializer_list.
This also works:
std::array<closure_type, sizeof...(calls)+1> tmp ={
nullptr,
std::forward<calls_t>(calls)...
};
tmp[0] = callbacks::foo(number);
return {std::make_move_iterator(std::begin(tmp)), std::make_move_iterator(std::end(tmp))};
the problem is callbacks::foo(number) within the initalization.
I have the following code:
#include<iostream>
using namespace std;
void saludo();
void despedida();
int main(){
void (*Ptr_Funciones[2])() = {saludo, despedida};
(Ptr_Funciones[0])();
(Ptr_Funciones[1])();
return 0;
}
void saludo(){
cout<<"\nHola mundo";
}
void despedida(){
cout<<"\nAdios mundo"<<endl<<endl;
}
Based on this, a few questions were generated which I investigated before asking but did not fully understand.
The questions are:
How do I make an array of functions, if they are of a different type?
I know that in C ++ this notation is used for undetermined parameters: (type var ...) The
thing is, I don't know how to interact with them inside the function.
If questions 1 and 2 are possible, can these points be combined when creating function
arrays?
I really have investigated. But I can't find much information, and the little I did find I didn't understand very well. I hope you can collaborate with me.
Thank you very much.
How do I make an array of functions, if they are of a different type?
You can, but you don't want to. It doesn't make semantic sense. An array is a collection of the same kind of thing. If you find that you need to make a collection of different kinds of things, there are several data structures at your disposal.
I know that in C++ this notation is used for undetermined parameters: (type var ...) The thing is, I don't know how to interact with them inside the function.
Here's how you can use the syntax you mention. They're called variadic functions.
If questions 1 and 2 are possible, can these points be combined when creating function arrays?
Erm, I can't imagine why/when a combination of these two would be needed, but out of intellectual curiosity, awayyy we go...
A modified version of the code from the reference link above that kinda does what you want (i've used a map instead of an array, cuz why not):
#include <iostream>
#include <cstdarg>
#include <unordered_map>
template<typename T>
using fooptr = void (*) (T *t...);
struct A {
const char *fmt;
A(const char *s) :fmt{s} {}
};
struct B : public A {
B(const char *s) : A{s} {}
};
void simple_printf(A *a...)
{
va_list args;
auto fmt = a->fmt;
va_start(args, a);
while (*fmt != '\0') {
if (*fmt == 'd') {
int i = va_arg(args, int);
std::cout << i << '\n';
} else if (*fmt == 'c') {
// note automatic conversion to integral type
int c = va_arg(args, int);
std::cout << static_cast<char>(c) << '\n';
} else if (*fmt == 'f') {
double d = va_arg(args, double);
std::cout << d << '\n';
}
++fmt;
}
va_end(args);
}
int main()
{
A a{"dcff"};
B b{"dcfff"};
std::unordered_map<size_t, fooptr<struct A>> index;
index[1] = simple_printf;
index[5] = simple_printf;
index[1](&a, 3, 'a', 1.999, 42.5);
index[5](&b, 4, 'b', 2.999, 52.5, 100.5);
}
This still really doesn't do what you wanted (i.e., give us the ability to choose from different functions during runtime). Bonus points if you understand why that's the case and/or how to fix it to do what you want.
Use a type alias to make things readable:
Live On Coliru
using Signature = void();
Signature* Ptr_Funciones[] = { saludo, despedida };
Prints
Hola mundo
Adios mundo
More flexible:
You can also use a vector:
Live On Coliru
#include <iostream>
#include <vector>
using namespace std;
void saludo() { cout << "\nHola mundo"; }
void despedida() { cout << "\nAdios mundo" << endl << endl; }
int main() {
vector Ptr_Funciones = { saludo, despedida };
Ptr_Funciones.front()();
Ptr_Funciones.back()();
}
Prints the same.
More Flexibility: Calleables of Different Types
To bind different types of functions, type-erasure should be used. std::function helps:
Live On Coliru
#include <iostream>
#include <functional>
#include <vector>
using namespace std;
void saludo(int value) { cout << "\nHola mundo (" << value << ")"; }
std::string despedida() { cout << "\nAdios mundo" << endl << endl; return "done"; }
int main() {
vector<function<void()>>
Ptr_Funciones {
bind(saludo, 42),
despedida
};
Ptr_Funciones.front()();
Ptr_Funciones.back()();
}
Prints
Hola mundo (42)
Adios mundo
Here is one solution that is possible, whether it fits your needs I'm not sure.
#include <Windows.h>
#include <iostream>
void saludo()
{
std::cout << "\nHola mundo" << std::endl;;
}
void despedida()
{
std::cout << "\nAdios mundo" << std::endl;
}
void* fnPtrs[2];
typedef void* (VoidFunc)();
int main()
{
fnPtrs[0] = saludo;
fnPtrs[1] = despedida;
((VoidFunc*)fnPtrs[0])();
((VoidFunc*)fnPtrs[1])();
std::getchar();
return 0;
}
When attempting to access a tuple's value via a scoped and typed enum, I get an error saying there is no matching type for std::get.
enum class User: std::size_t {
FirstName = 1,
LastName = 2,
};
std::tuple<std::string, std::string> user("Bobby", "Bean");
// Error
std::cout << std::get<User::FirstName>(user) << std::endl;
Given that std::get expects type std::size_t and the underlying type of the enum is also std::size_t, why does this fail?
I'm aware that I can cast the value of the enum, but I'm not sure why that would be necessary given that both underlying types are the same. With an unscoped enum, this works just fine.
Enum classes really aren't integers on the surface. Just like a struct containing just an int is not an int.
The C++ standard way back to the integer representation is this:
using UserUndT = std::underlying_type<User>::type;
std::cout <<
std::get<static_cast<UserUndT>(User::FirstName)>(user) << std::endl;
Also, check out this question: Using enable_if and underlying_type in function signature in VS2012
An alternative worth considering: (C++14)
#include <iostream>
#include <tuple>
struct FirstName {
std::string val;
};
struct LastName {
std::string val;
};
using FullName = std::tuple<FirstName,LastName>;
int main() {
auto user = FullName({"John"},{"Deer"});
std::cout << std::get<FirstName>(user).val << std::endl;
std::cout << std::get<LastName>(user).val << std::endl;
}
to get what you want you can do:
namespace User{enum User:size_t{FirstName,LastName};};
then you will have the bare typed enum again.
The namespace solution works but not inside a function or class. An alternative is as follows:
#include <iostream>
#include <tuple>
#include <vector>
#include <string>
using namespace std;
int main()
{
struct Test{enum size_t{first, second, third};};
vector<tuple<int, string, bool>> mt;
mt.emplace_back(make_tuple(10, "hello", true));
cout << get<Test::first>(mt[0]) << ' ' << get<Test::second>(mt[0]) << ' ' << get<Test::third>(mt[0]) << endl;
return 0;
}
In the ideal case, I would like to use the ClassVariant in the following way:
// store & retrieve int
map<string, ClassVariant> mapValues;
mapValues["int_fieldX"] = ClassVariant(20);
int fieldX = (mapValues["int_fieldX"])();
// Or int fieldX = (mapValues["int_fieldX"]);
However, I can ONLY implement the following code that requires the retrieving statement to feed the type info as follows:
int fieldB = (mapValuesTwo["int_fieldB"])(int(0));
As you can see int(0) is provided as type info. Is there a way that I can remove this limitation. So that the type info is NOT needed.
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/variant.hpp>
using namespace std;
typedef boost::variant<int, double, string> VarIntDoubleString;
class ClassVariant
{
public:
ClassVariant() : m_value(int(0)) {}
ClassVariant(VarIntDoubleString _val) : m_value(_val) {}
template<typename T>
T operator()(const T&) const
{
return boost::get<T>(m_value);
}
private:
VarIntDoubleString m_value;
};
int main(void)
{
map<string, ClassVariant> mapValuesTwo;
// store & retrieve int
mapValuesTwo["int_fieldB"] = ClassVariant(20);
int fieldB = (mapValuesTwo["int_fieldB"])(int(0));
cout << "fieldB: " << fieldB << endl;
// store & retrieve string
mapValuesTwo["int_fieldD"] = ClassVariant("Hello world");
string fieldD = (mapValuesTwo["int_fieldD"])(string(""));
cout << "fieldD: " << fieldD << endl;
}
// Output
fieldB: 20
fieldD: Hello world
You can't do this, template argument deduction works only on the parameters, not on the return value of a function. Your best choice is to ditch operator() for a normal function like get<T>(). I can't point to the relevant line in the standard though, too obscure for me.
Note: if such a thing was possible, my guess would be that boost::variant would already have a get function where specifying T is not requried.
EDIT: see this question
You SHOULD use boost::variant together with visitor to access the value in it. see here