I'm new to C++ and I'm trying to pass a collection of a nonvariable amount strings to a function that exists in separate class file in an easy to read manner as such:
//main in Caller.cpp
int main()
{
string details[] = {"Name","Height","Weight"};
/* vector<string> detailsV = {"Name","Height","Weight"};
* Would like to use a vector but can't do this because vector cannot be
* initialized to = {...} in C++
*/
Person p = Person();
p.inspectDetails(details);
}
//Person class in Person.cpp
void inspectDetails(string details [])
{
int sz = sizeof(details); // this will result in details = "Name" only
}
I've tried:
//Person class in Person.cpp
<template size_t N>
void inspectDetails(string (&details)[N])
{
int sz = sizeof(details);
}
However, I don't now how to let the main in the Caller class know about the <template size_t N> which might allow me to use an array of a non-explicit amount. I seem to get an error of "no suitable conversion of std:string[3] to std:string" when trying to call inpectDetails this way.
What is the best way to pass a collection of strings of a non-explicit amount to a function outside of the Caller class whilst maintaining the ability to hardcode the collection's contents like so Collection c = {"...", "...", "..."} in C++?
Is there an easier way to pass the full collection of strings to a function with a pointer to a vector or something of that sort?
Use a std::vector< std::string > and pass it by reference if you need to change its contents, const reference if you don't need to change them. This is the simplest, most flexible, and clearest way.
Thus:
void inspectDetails( std::vector< std::string > & details );
std::vector< std::string > details = { "Name","Height","Weight" };
inspectDetails( details );
cf. http://en.cppreference.com/w/cpp/container/vector
Passing by const reference is an option. This is what a possible program might look then:
#include <iostream>
#include <string>
#include <vector>
void inspectDetails( const std::vector<std::string> & details )
{
int v = details.size();
std::cout<<v<<std::endl;
}
int main()
{
std::vector<std::string> details = {"name", "height", "weight"};
inspectDetails(details);
return 0;
}
Rob K answered right to you question. I will add that sometimes it's usefull to use std::array rather than a simple array : http://en.cppreference.com/w/cpp/container/array For example, you can easily know the size of your array.
Related
Guys I have a function like this (this is given and should not be modified).
void readData(int &ID, void*&data, bool &mybool) {
if(mybool)
{
std::string a = "bla";
std::string* ptrToString = &a;
data = ptrToString;
}
else
{
int b = 9;
int* ptrToint = &b;
data = ptrToint;
}
}
So I want to use this function in a loop and save the returned function parameters in a vector (for each iteration).
To do so, I wrote the following struct:
template<typename T>
struct dataStruct {
int id;
T** data; //I first has void** data, but would not be better to
// have the type? instead of converting myData back
// to void* ?
bool mybool;
};
my main.cpp then look like this:
int main()
{
void* myData = nullptr;
std::vector<dataStruct> vec; // this line also doesn't compile. it need the typename
bool bb = false;
for(int id = 1 ; id < 5; id++) {
if (id%2) { bb = true; }
readData(id, myData, bb); //after this line myData point to a string
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
}
}
Or is there a better way to do that without template? I used c++11 (I can't use c++14)
The function that you say cannot be modified, i.e. readData() is the one that should alert you!
It causes Undefined Behavior, since the pointers are set to local variables, which means that when the function terminates, then these pointers will be dangling pointers.
Let us leave aside the shenanigans of the readData function for now under the assumption that it was just for the sake of the example (and does not produce UB in your real use case).
You cannot directly store values with different (static) types in a std::vector. Notably, dataStruct<int> and dataStruct<std::string> are completely unrelated types, you cannot store them in the same vector as-is.
Your problem boils down to "I have data that is given to me in a type-unsafe manner and want to eventually get type-safe access to it". The solution to this is to create a data structure that your type-unsafe data is parsed into. For example, it seems that you inteded for your example data to have structure in the sense that there are pairs of int and std::string (note that your id%2 is not doing that because the else is missing and the bool is never set to false again, but I guess you wanted it to alternate).
So let's turn that bunch of void* into structured data:
std::pair<int, std::string> readPair(int pairIndex)
{
void* ptr;
std::pair<int, std::string> ret;
// Copying data here.
readData(2 * pairIndex + 1, ptr, false);
ret.first = *reinterpret_cast<int*>(ptr);
readData(2 * pairIndex + 2, ptr, true);
ret.second = *reinterpret_cast<std::string*>(ptr);
}
void main()
{
std::vector<std::pair<int, std::string>> parsedData;
parsedData.push_back(readPair(0));
parsedData.push_back(readPair(1));
}
Demo
(I removed the references from the readData() signature for brevity - you get the same effect by storing the temporary expressions in variables.)
Generally speaking: Whatever relation between id and the expected data type is should just be turned into the data structure - otherwise you can only reason about the type of your data entries when you know both the current ID and this relation, which is exactly something you should encapsulate in a data structure.
Your readData isn't a useful function. Any attempt at using what it produces gives undefined behavior.
Yes, it's possible to do roughly what you're asking for without a template. To do it meaningfully, you have a couple of choices. The "old school" way would be to store the data in a tagged union:
struct tagged_data {
enum { T_INT, T_STR } tag;
union {
int x;
char *y;
} data;
};
This lets you store either a string or an int, and you set the tag to tell you which one a particular tagged_data item contains. Then (crucially) when you store a string into it, you dynamically allocate the data it points at, so it will remain valid until you explicitly free the data.
Unfortunately, (at least if memory serves) C++11 doesn't support storing non-POD types in a union, so if you went this route, you'd have to use a char * as above, not an actual std::string.
One way to remove (most of) those limitations is to use an inheritance-based model:
class Data {
public:
virtual ~Data() { }
};
class StringData : public Data {
std::string content;
public:
StringData(std::string const &init) : content(init) {}
};
class IntData : public Data {
int content;
public:
IntData(std::string const &init) : content(init) {}
};
This is somewhat incomplete, but I think probably enough to give the general idea--you'd have an array (or vector) of pointers to the base class. To insert data, you'd create a StringData or IntData object (allocating it dynamically) and then store its address into the collection of Data *. When you need to get one back, you use dynamic_cast (among other things) to figure out which one it started as, and get back to that type safely. All somewhat ugly, but it does work.
Even with C++11, you can use a template-based solution. For example, Boost::variant, can do this job quite nicely. This will provide an overloaded constructor and value semantics, so you could do something like:
boost::variant<int, std::string> some_object("input string");
In other words, it's pretty what you'd get if you spent the time and effort necessary to finish the inheritance-based code outlined above--except that it's dramatically cleaner, since it gets rid of the requirement to store a pointer to the base class, use dynamic_cast to retrieve an object of the correct type, and so on. In short, it's the right solution to the problem (until/unless you can upgrade to a newer compiler, and use std::variant instead).
Apart from the problem in given code described in comments/replies.
I am trying to answer your question
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
Before that you need to modify vec definition as following
vector<dataStruct<void>> vec;
Now you can simple push element in vector
vec.push_back({id, &mydata, bb});
i have tried to modify your code so that it can work
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct dataStruct
{
int id;
T** data;
bool mybool;
};
void readData(int &ID, void*& data, bool& mybool)
{
if (mybool)
{
data = new string("bla");
}
else
{
int b = 0;
data = &b;
}
}
int main ()
{
void* mydata = nullptr;
vector<dataStruct<void>> vec;
bool bb = false;
for (int id = 0; id < 5; id++)
{
if (id%2) bb = true;
readData(id, mydata, bb);
vec.push_back({id, &mydata, bb});
}
}
There is a class say Person which has member variables name, email, mobile, gender.
Now, we are getting this information in an array.
std::vector<std::string> a[] = {"XYZ", "xyz#mail.com", "1234567890", "Male"};
Person p;
Now, instead of writing it like:
p.name = a[0]; p.email = a[1]....
I want something like this for dynamic allocation as well as for reducing code lines:-
std::vector<std::string> b[] = {"name", "email", "mobile", "gender"};
int len = a.size();
for (int i=0; i < len ; i++)
{
set_value(p, b[i], a[i]);
}
How to write a function like set_value, or is there any way to do something like this in c++ ?
Right now in above example we have a vector size of 4, but it can be in size of 10 or 50 or more also. In that case if we don't have the way of setting the values dynamically then we might have to write same number of lines for setting every member variable .. .?
I think one of the solutions in which you are talking about is to implement all the fields of the Person class as a map<K, V>, which will store all of yours properties. In this case you will be able to refer to the value by the key of a map.
I would not recommend this solution for you. You can think of set_value function as a way in which the names from array a should refer to the name of the properties or rather how does those names should be linked to the functions which could invoke a proper property-right set method.
If those setting functions you are interested in use the same base type as a parameter, you could create map of strings and function pointers.
#include <map>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
class Person{
std::map<std::string, std::string> _properties;
public:
Person() = default;
~Person() = default;
void set_values(vector<string> & fields, vector<string> & values){
if(fields.size() != values.size()) return;
for(int i = 0; i < fields.size(); ++i){
_properties.insert_or_assign(fields[i], values[i]);
}
}
void print(){
for (auto const &it : _properties)
std::cout << it.first << " => " << it.second << '\n';
}
};
int main(){
Person p;
vector<string> fields = {"email", "name"};
vector<string> values = {"a#b.com", "Andrew"};
p.set_values(fields, values);
p.print();
vector<string> fields2 = {"name"};
vector<string> values2 = {"Tom"};
p.set_values(fields2, values2);
p.print();
return 0;
}
This minimal working example shows what you want to get and it has a lot of constraints, such as it assumes that all of the values are stored as a std::string which can not be a good in every case. It produces a following output after applying the first set of fields and values:
email => a#b.com
name => Andrew
After the second one, the email stays the same but name is updated as follows:
email => a#b.com
name => Tom
I've compiled it using g++ version 7.1 using using following command:
g++ --std=c++1z main.cpp on my Fedora 26.
Well, there are no easy way to set a variable by name... There are library that allows to do something like that (for ex. boost fusion) but in practice, you could also write a simple function if you have only a few functions to write on a few classes.
One simple possibility assuming you want to reuse the code that fill a object:
void set_values_of(Person &p, const std::vector<std::string> &data)
{
assert(data.size() == 4); // put whatever error handling you want...
p.name = data[0];
p.email = data[1];
p.mobile = data[2];
p.gender = data[3];
}
And if you prefer, you might change second argument for another source (for ex. a stream or one line a string). At that point, it really depends on your application.
If your prefer immuable objects, you might also consider having a factory free function:
Person create_from(const std::vector<std::string> &data) { ... }
Here's my issue, I would like to call the getters/setters of one of my objects, but not directly, I want to do it by using a std::string.
I found this but it won't work on my case I think it is because my function aren't defined in my main method but in my square class. Also my function are not all defined the same way there's void(std::string) std::string() void(int)...
here's an exemple of what a would like to do.
my object square
#include <map>
#include <functional>
#include <string>
class Square{
private:
std::string name;
int width;
float happinessPoint; //extremly important for your square.
public:
void setName(std::string);
void setWidth(int);
void setHappinessPoint(float);
std::string getName()
int getWidth()
float getHappinnessPoint()
}
and my main
#include "Square.h/cpp"
int main(){
Square square = Square("Roger",2,3.5);
// here in my magicalFunction I ask to the users the new values for my square (all in std::string for now)
vector <std::string> newValueForSquare = magicalFunction();
for (unsigned int i=0; i < newValueForSquare.size(), i++){
//here I have a function which tell me if my std::string
// is in fact a float or an int
// and I would like to call each of my setters one by one to
// sets my Square to some value I asked to the user before all that.
// something like that:
// someFunction("setName","Henry")
}
}
I hope i have been clear it's pretty hard to explain something you don't know how to do. If you want me to be more specific tell me and I'll do what I can.
EDIT: What I want to do is to call for example my square.setName() with a str::string without writting this square.setName in my main.
To call functions, based on a string, you have some choices. Before I list the choices, please search the internet for "C++ factory design pattern".
If-else ladder
Lookup table
Map / Associative array
Hash table
There may be other methods, but the above come to mind.
if-else ladder (a.k.a. switch)
The problem with this method is that the switch statement doesn't work with strings nor text literals. So you'll have to suffice with if statements:
if (string == "Roger")
{
Process_Roger();
}
else if (string == "Felicity")
{
Process_Felicity();
}
else
{
Display_Error_Message();
}
Anytime you need to add a new string, you will have to add another "else if" statement to the ladder. Not only do you have to change the code, but you also have to retest it.
Lookup Table
You will need to understand function pointers for this technique and the map technique. Consider this a prerequisite.
Use a structure for mapping text strings to function pointers:
struct Text_Function_Pointer
{
const char * name;
Function_Pointer p_function;
};
static const Text_Function_Pointer table[] =
{
{"Larry", Process_Larry},
{"Felicity", Process_Felicity},
};
static const unsigned int table_size =
sizeof(table) / sizeof(table[0]);
//...
for (unsigned int i = 0; i < table_size; ++i)
{
if (search_name == table[i].name)
{
// Execute the processing function.
table[i].p_function(search_name);
break;
}
}
An issue with this technique is that all the function pointers must have the same signature. This is true for the map as well.
A nice feature is that the data in the table is constant, so it can be placed in Read-Only Memory.
Also, to add more associations, add an entry to the the table. The search / processing function hasn't changed, so it doesn't need to be tested again.
Map / Associative Array
Prerequisite: Function pointers.
Declare a std::map<std::string, Function_Pointer_Type>. Add your names and functions to the map:
std::map<std::string, Function_Pointer_Type> dispatch_table;
dispatch_table["Roger"] = Process_Roger;
dispatch_table["Felicity"] = Process_Felicity;
dispatch_table["Larry"] = Process_Larry;
//...
// Execute appropriate processing function:
(dispatch_table[search_name])();
One issue with this method is that the std::map data structure needs to be initialized; it can't be directly accessed or loaded from executable code.
Again, all functions must have the same signature.
Hash Table
The idea here is to have an array of function pointers or an array of structures with text & function pointers. Create a hash function that generates a unique array index based on the name string. Use the index to get the function pointer from the array, then execute the function via the function pointer.
Several solutions are available to you. You basically want to parse user input to fill your Square class attribute.
One way is to use the std::stoi family of functions:
std::vector<string> values { "Roger", "2", "3.5" };
std::string name = values[0]; // No problem, two strings
int width = std::stoi(values[1]); // stoi = stringToInt
float happiness = std::stof(values[2]); // stof = stringToFloat
I'm not sure why you'd need the for loop, unless there is something I didn't understand in your question. I'll update my answer accordingly.
Update 1
After reading other answers, I would like to propose my solution to your problem. As stated several times in my comments, this is not an easy answer !
I needed such a class to write a generic test engine, and this is the code I used. It works really well with any type of function (except for routines with a return type of void -- a simple template specialization would solve it though)
# include <functional>
# include <tuple>
template<int ...>
struct seq
{
};
template<int N, int ...S>
struct gens : gens<N - 1, N - 1, S...>
{
};
template<int ...S>
struct gens<0, S...>
{
typedef seq<S...> type;
};
struct callable_base
{
virtual void operator()() = 0;
virtual ~callable_base()
{ }
};
class Task
{
private:
template<class RT, class Functor, class ...Args>
struct functor : public callable_base
{
functor(RT& result, Functor func, Args ...args)
: _ret(result)
{
_func = func;
_args = std::make_tuple(args...);
}
void operator()()
{
_ret = call(typename gens<sizeof...(Args)>::type());
}
template<int ...S>
RT call(seq<S...>)
{
return (_func(std::get<S>(_args)...));
}
private:
std::function<RT(Args...)> _func;
std::tuple<Args...> _args;
RT& _ret;
};
public:
Task()
{
_functor = nullptr;
}
template<class RT, class Functor, class ...Args>
Task(RT& result, Functor func, Args... args)
{
_functor = new functor<RT, Functor, Args...>(result, func, args...);
}
void operator()()
{
(*_functor)();
}
~Task()
{
delete _functor;
}
private:
callable_base *_functor;
};
The idea behind this code is to hide the function signature in the inner class Task::functor and get the return value in the first parameter passed to the Task(...) constructor. I'm giving this code first because I think it might help some people, but also because I think it is an elegant solution to your problem. Bear in mind that to understand most of the code, you need solid C++ knowledge. I'll detail the code in subsequent updates if needed.
Here's how you'd use it:
int main()
{
int retVal;
std::string newName;
std::map<std::string, Task *> tasks {
{"setName", new Task(retVal, &Square::setName, &newName)}
...
}
/* Modify the name however you want */
...
tasks["setname"]();
}
This whole class could be optimized, of course, primarily thanks to C++14 and move semantics, universal references and all, but I kept it simple ~
A major problem is that you have to use pointers if you don't know the values of the parameters at the time you fill the task map. I'm working on another version to simplify this aspect, but I wanted to show you that C++ is not designed to do what you ask simply. Maybe you come from a functional or JS world, in which this would be trivial x)
Update 2
I just wanted to point out that with C++14, you could omit the first 3 structures that are here to help me expand my tuple in an argument list using interger_sequence
I'm trying to create a program that can read some data from 2 files.
The first file is the header, that describe the data structure (dimensions, data type, extents, etc...), and the second is the raw data.
To handle different data type at runtime, I created a templated class that will be used as a container for the data. Depending on the data type read in the header, I will create a specialized class of the container to store the data.
However, now I'm facing another issue. How can I create a dynamic multidimensional array at runtime ?
I first thought doing it the old fashion way, and put a pointer into the storage class, and creating some loops ( = to the dimensionality) to create a new array (new array[size]).
But I don't think it's a very clean way of doing it.
I also thought about stacking std::vector, but I don't know the dimensionnality before runtime.
Then I considered using boost to create a multi_array, and using resize() to update the extent of my array at runtime, but it is required to know the dimension when creating the array (multi_array< type, dim > variable).
As I want to be able to access this in all my class (for future processing, etc...), I don't see how to put that in my class, as I will only know the dimensionnality at runtime.
Is it possible to create a base pointer of multi_array in my class, and declare it later (when I will know the dimension needed) ?
Or is there another way to do this ?
My final goal is to create a multidimensional array at runtime, that I can access in all my class.
Thank you.
Edit: Most of the topics I read about it are for fixed dimensional array, with a variating size. But in my case, dimension also varies.
Update: Your answer inspired me an idea Hugues.
I already have a templated class to read the data, but for now it only takes as parameter, the data type.
I'm thinking adding the dimensionnality to it and create a class like that:
storageClass< data_type, data_dimension > myStorage(filename, data_extent, data_endian, data_encoding);
This way, I can also template the dimensionnality of the data, and create a multidimensionnal array (using boost for example).
I will let you know if it worked.
Thank you.
Update 2: Apparently it's not possible cause templates expect constant expression. I cannot pass the variable 'dimension' (even if it's a fixed value in this case, but it's not define at compile-time).
So I guess my best option is to create a variadic getter in the custom storage class, and return the corresponding value. The problem is that a variadic method involve to parse the arguments, and as this is a method that will be frequently called, it's not optimal.
It is likely necessary to create a custom class.
One idea is to have it contain two main members m_dims and m_data:
#include <vector>
#include <cassert>
using std::size_t;
template<typename T> class MultiArray {
public:
MultiArray(const std::vector<int>& dims)
: m_dims(dims), m_data(product(m_dims)) { }
const std::vector<int>& dims() const { return m_dims; }
const T& operator[](const std::vector<int>& indices) const {
return m_data[index(indices)];
}
T& operator[](const std::vector<int>& indices) {
return m_data[index(indices)];
}
private:
std::vector<int> m_dims;
std::vector<T> m_data;
static size_t product(const std::vector<int>& dims) {
size_t result = 1;
for (size_t i = 0; i<dims.size(); ++i) result *= size_t(dims[i]);
return result;
}
size_t index(const std::vector<int>& indices) const {
size_t v = 0;
for (size_t i = 0; i<m_dims.size(); ++i) {
assert(indices[i]>=0 && indices[i]<m_dims[i]);
if (i) v *= size_t(m_dims[i]);
v += size_t(indices[i]);
}
return v;
}
};
int main() {
MultiArray<float> ar{std::vector<int>{2, 3}};
ar[std::vector<int>{0, 0}] = 1.f;
ar[std::vector<int>{0, 1}] = 2.f;
ar[std::vector<int>{0, 2}] = 3.f;
ar[std::vector<int>{1, 0}] = 4.f;
ar[std::vector<int>{1, 1}] = 5.f;
ar[std::vector<int>{1, 2}] = 6.f;
}
See code in http://coliru.stacked-crooked.com/a/92e597d4769f9cad
Sorry for the confusing title, basically I have created two classes, one is an object, and the other being a box that contains an array of such objects. so what I want to do is create a function/constructor inside the object class that takes in an array of ints and stores them inside the box. I want to be able to call this function through the box class constructor to initialize these objects. So ive tried something like below but it isnt working at all, since only the first value of the array gets passed through. What am I doing wrong?
#include <iostream>
#include <string>
class object{
string objectName;
int values[];
public:
void createObject(int[]);
}
class Box{
object objects[100];
public:
Box();
}
Box::Box (void){
int array1[2];
int array2[15];
object[1].createObject(array1);
object[2].createObject(array2);
}
Object::Object(int Values[]){
values = Values;
}
You should really use std::vector. The problem with arrays is that they decay to pointers when passed as arguments to functions. As a consequence, If you want to store a private copy of the elements you are forced to use heap-allocated objects and consequently do memory management by hand (with all the pain it causes).
It is much better to rely on data members that permit applying the rule of zero.
Here's a tentative solution:
#include <iostream>
#include <string>
#include <vector>
class object {
public:
object(std::vector<int> const& v, std::string const& object_name): v_(v.begin(), v.end()), object_name_(object_name) {}
private:
std::vector<int> v_;
std::string object_name_;
};
class box {
public:
box(std::vector<object> const& objects): objects_(objects) {};
private:
std::vector<object> objects_;
};
I recommend you instead use a std::vector. Arrays don't really work well being passed to functions. When you define Object::Object(int Values[]) you are simply passing the first element of this array by value. If you were to use vectors, the function would look like this:
Object::Object(std::vector<int> &Values):
values(Values)
{
}
The problem with the code is in your thinking on what the array is. In C++, all an array is, is a memory pointer. The language allows you to pass an index into the array pointer to access whatever chunk of data lives at that index.
Whenever you pass arrays between functions or classes, pass the array name only. It will be interpreted as a pointer, and won't copy any data. When you do this, you must also pass the length of the array.
Granted, most people stick with vector<> because it's easier, takes care of memory leaks (mostly) and is VERY efficient. But I like doing it myself. It's good for you. I would try:
#include <iostream>
#include <string>
class Object
{
string _objectName;
int *_values;
int _myLength;
Object();
~Object();
void createObject(int *pValues, int arrLength);
}
class Box
{
_Object objects[100];
Box();
}
Box::Box(void) {
int array1[2];
int array2[15];
object[1].createObject(array1, 2);
object[2].createObject(array2, 15);
}
Object::Object() {
_values = null_ptr;
_myLength = 0;
}
Object::~Object() {
delete[] _values;
}
void Object::createObject(int *pvalues, int arrLength) {
_myLength = arrLength;
_values = new int[_myLength];
for(int ndx=0; ndx<arrLength; ndx++) {
_values[ndx] = pvalues[ndx];
}
}
-CAUTION-
I just adapted your code you provided, and added some conventions. There are a couple places in the code where I'm not sure what the purpose is, but there you go. This should give you a good head start.