I am getting the following errors:
'<': illegal, left operand has type 'const_Ty'
'>: illegal, right operand has type 'const_Ty'
in the below code.
It's a relative simple iterator on a function pointer map where the functions are of the form void (Game::*)(UINT). I check the value against a float, then run the function.
The problem seems to be in the for line, although I've got another substantially similar for loop somewhere else that works without a problem.
using FuncPtr = void (Game::*)(UINT);
std::map<FuncPtr, float> funcDelayedTriggerMap;
void Game::PollProcessDelayedTriggers()
{
for (std::map<FuncPtr, float>::iterator it = funcDelayedTriggerMap.begin(); it != funcDelayedTriggerMap.end(); ++it)
{
float currentS = m_timer.GetElapsedSeconds();
if (it->second < currentS)
{
(this->*(it->first))(UINT_MAX);
funcDelayedTriggerMap.erase(it->first);
}
}
}
Member function pointers don't implement operator<, which is the default sorting function std::map uses.
Member function pointers only implement operator== and operator!= .
An easy way to fix this woud be to have a separate key and put the function pointer into the value of the map, e.g.:
std::map<int, std::pair<FuncPtr, float>>
or if you don't need the fast lookup of std::map, a simple vector would also work:
std::vector<std::pair<FuncPtr, float>>
An alternative approach would be to use the function pointer type as key:
using FuncPtr = void (Game::*)(int);
// Just a helper to get a unique type for each function pointer
template<FuncPtr ptr>
struct Tag {};
struct DelayedTrigger {
FuncPtr ptr;
float value;
DelayedTrigger() : ptr(nullptr), value(0.0f) {}
DelayedTrigger(FuncPtr _ptr, float _value) : ptr(_ptr), value(_value) {}
};
std::map<std::type_index, DelayedTrigger> funcDelayedTriggerMap;
void Game::PollProcessDelayedTriggers()
{
for (std::map<std::type_index, DelayedTrigger>::iterator it = funcDelayedTriggerMap.begin(); it != funcDelayedTriggerMap.end(); ++it)
{
float currentS = 1.0;
if (it->second.value < currentS)
{
(this->*(it->second.ptr))(0);
funcDelayedTriggerMap.erase(it->first);
}
}
}
This essentially uses the specific function pointer as a unique key.
You could then add new entries like this:
funcDelayedTriggerMap.emplace(typeid(Tag<&Game::DoIt>), DelayedTrigger{&Game::DoIt, 1.0f});
// or
funcDelayedTriggerMap[typeid(Tag<&Game::DoIt>)] = {&Game::DoIt, 1.0f};
And check if a function is present:
if(funcDelayedTriggerMap.contains(typeid(Tag<&Game::DoIt>))) {
// ...
}
This however only works if you know all the functions you want to use with the map at compile time.
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 are two integers x and 7 which are randomly generated integers. The program uses a red black tree member fucntion insert to insert new values into the tree.
I'm not understand the arguments of the insert function, more specifically the use of
(void*)x and (void*y)
Here's the function call in main
rbt.rbtree_insert(t, (void*)x, (void*)y, compare_int);
Here's the insert function defined
void RBTree::rbtree_insert(rbtree t, void* key, void* value, compare_func compare)
{
node inserted_node = new_node(key, value, RED, NULL, NULL);
if (t->root == NULL)
{
t->root = inserted_node;
}
else
{
node n = t->root;
while (1)
{
int comp_result = compare(key, n->key);
if (comp_result == 0)
{
n->value = value;
return;
}
else if (comp_result < 0)
{
if (n->left == NULL)
{
n->left = inserted_node;
break;
}
else
{
n = n->left;
}
}
else
{
assert(comp_result > 0);
if (n->right == NULL)
{
n->right = inserted_node;
break;
}
else
{
n = n->right;
}
}
}
inserted_node->parent = n;
}
insert_case1(t, inserted_node);
verify_properties(t);
}
void* is a type. More specifically, it is a pointer type. Even more specifically, it is a special pointer type that can point to any type. void* is a way to implement polymorphism in C. It's usually not recommended to use void* in C++.
(void*)x is an explicit type conversion also known as C-style type cast expression. The type of variable x is converted to void*. The use of C-style casts is discouraged in C++.
Presumably the type of x is not void* and therefore a conversion is needed to match the type of the argument.
The author of this code uses the most abstract pointer type available in C++: void*. It is a pointer so "something". What this "something" might be is not defined at compile time. (void*)x is a type cast in legacy C-syntax, that interprets any other pointer as void*. The prefered C++ syntax is static_cast<void*>(x), though void* should only be used, when there are very, very good reasons to do so.
I understand, that this is legacy code, you have been asked to work on. So let's be frank, there is quite a lot wrong with it.
There are exactly two reason to implement a red-black-tree class: learning data structures and std::map<> as part of a standard library implementation. In all other cases, there is no reason not to prefer std::map<>. It'd save you from all the design pitfalls, the author of this code has stepped in.
It is redundant to add the name of the class to the name of a member function. Call it RBTree::insert() instead of RBTree::rbtree_insert(). When you use consistent member function names for different container types, you can easily exchange them in future, without having to change all the calls to all the member functions. The standard containers are a good source of inspiration here.
A red-black-tree instance always has to work with the same compare function. To pass the compare function again and again to insert(), find(), erase(), etc. is not only redundant but also error prone. Either have it as a parameter to the constructor, or better as a template parameter to a red-black-tree class template.
In any case a red-black-tree should be a template, that has a key and a value type as template parameters. Then all the member functions like insert(), find(), etc. can be typesafe.
Why should one pass the this object explicitly to a member function. I guess, the author of that code has been trying to write Python in C++. In C++ this is always implicit for member functions, in contrast to self in Python.
Putting it all together I'd propose an interface like this:
template<typename key_t,
typename value_t,
typename Compare = std::less<key_t>>
class rb_tree {
void insert(const key_t& key, const value_t& value);
void erase(const key_t& key);
value_t find(const key_t& key);
};
As you see, we now define types for keys and values and use them in insert(), erase() and find(). These functions can never try to walk a tree with int keys as if it had std::string keys. They also always use the same compare function, which defaults to the operator <.
The usage is a lot better to understand as well:
rb_tree<int, int> rbt; // we use the default comparison
int x = 42;
int y = 4711;
rbt.insert(x, y);
assert(rbt.find(x) == y);
rbt.erase(x);
Well, actually my real suggestion is to drop than homegrown red-black-tree and use std::map<> instead. Its usage is even more intuitive:
std::map<int, int> rbt;
int x = 42;
int y = 4711;
rbt[x] = y;
assert(rbt[x] == y);
rbt.erase(x);
Can anyone explain to me why the following segment compiles but the commented line after doesn't?
struct tObj
{
int data;
int moreData;
}
...
void funcToCall (tObj *obj, int moreData)
{
//Useful stuff here
}
void mainFunction ()
{
vector<tObj>::iterator it = vectorOfObjects.begin(); //assumes vectorOfObjects is already defined
while (it != vectorOfObjects.end())
{
funcToCall (&(*it), 0); //This line works
funcToCall (it, 0); //This line produces an error
it++;
}
}
The error produced is this:
error: cannot convert ‘std::vector<tObj>::iterator {aka __gnu_cxx::__normal_iterator<tObj*, std::vector<tObj> >}’ to ‘tObj*’
Any ideas on why &(*it) works but just plain it doesn't? Logically they are the same, aren't they?
Because doesn't * mean to dereference and & mean pass by reference aka cancelling each other out?
it is an iterator object, passing it as-is would mean you're trying to pass an object of type vector<tObj>::iterator for a function expecting tObj*, and thus the error.
When you do *it you'd get the underlying object the iterator is representing and when you apply & atop that, you get that object's address, which is of type tObj* which agrees with the function's argument type and thus no error.
That the code would be compiled you have to declare an overloaded function like
void funcToCall ( std::vector<tObj>::iterator it, int moreData)
{
//Useful stuff here
}
In general case types tObj * and vector<tObj>::iterator are different types though in some old realizations of std::vector its iterator is indeed defined as a pointer..
I am building a C++ program that needs to store a map of strings to function pointers. However, every function may have different return types and parameters. The way I am attempting to solve this problem is by creating the functions as taking an array of void pointers and returning an array of void pointers, and then casting the arguments and return values as needed.
To figure out how this would work, I'm trying to build a simple dummy, but can't get it to compile. I've tried a number of things, but I keep getting different errors. here's an example:
#include <string>
#include <iostream>
#include <map>
using namespace std;
void** string2map(void** args){
//takes a string of the form "key:value;key:value;..." and returns a map<string,string>
string st = *((string**) args)[0];
map<string, string> result = map <string, string>();
//code doesnt matter
return (void*) &((void*) &result);
}
int main(){
string test = "hello:there;how:are you?";
map<string, string> result = *(map<string, string>**)string2map((void*) &((void*) &test))[0];
return 0;
}
when I try to compile, I get:
void.cpp: In function 'void** string2map(void**)':
void.cpp:12:34: error: lvalue required as unary '&' operand
void.cpp: In function 'int main()':
void.cpp:17:89: error: lvalue required as unary '&' operand
Obviously there are plenty of things wrong here, but I really just don't know where to start. Can anyone either show me what's wrong with the code above, or give me an alternative to the way I am currently doing it?
NOTE
The reason I am returning a void** instead of just void* is that there might be a circumstance where I need to return multiple values of different types. An example would be if, above, I wanted to return both the resulting map AND the number of entries in the map. I haven't even gotten to the point of figuring out how to construct that array yet, though.
EDIT
So based on the responses so far, it seems pretty clear that this is the wrong way of solving this problem. With that in mind, can anyone suggest a better one? I need to be able to store the various function in a single map, which means I need to be able to define a single data type to functions that take and return different types. And it IS important to be able to return multiple values.
You're converting a map<string,string> to a void**, returning it then converting it back to a map<string,string. Why not just return a map<string,string>? It's also called string2map which implies you will only ever call it with a string (backed up by the fact you pass in a string, which is converted to a void** then converted straight back). Unless you have a good reason to convert to and from void** all over the place this is probably what you need:
#include <string>
#include <iostream>
#include <map>
using namespace std;
map<string, string> string2map(string st){
map<string, string> result = map <string, string>();
//code doesnt matter
return result;
}
int main(){
string test = "hello:there;how:are you?";
map<string, string> result = string2map(test);
return 0;
}
EDIT:
I've just reread your question. You might want to look up Generalised Functors and look at Boost's std::function as possible solutions to this problem. It's possible to change the return type of a function via a wrapper class, something like:
template< class T >
class ReturnVoid
{
public:
ReturnVoid( T (*functor)() ) : m_functor( functor ) {}
void operator() { Result = functor(); }
private:
T (*m_functor)();
T Result;
};
// Specialise for void since you can't have a member of type 'void'
template<>
ReturnVoid< void >
{
public:
ReturnVoid( T (*functor)() ) : m_functor( functor ) {}
void operator() { functor(); }
private:
T (*m_functor)();
};
Using this as a wrapper might help you store functors with different return types in the same array.
Ignoring my own horror at the idea of blatantly throwing type safety to the wind, two things spring immediately to mind.
First, what exactly do you think will be pointed to when string2map goes out of scope?
Second is that you don't have to cast to void*. Void* gets special treatment in C++ in that anything can be cast to it.
If you insist on trying to push this, I'd start by changing the return type to void, and then take the void* as an input parameter to your function.
For example:
void string2map(void* args, void* returnedMap);
This way you'd have to instantiate your map in a scope that will actually have a map to point to.
$5.3.1/3 - "The result of the unary & operator is a pointer to its
operand. The operand shall be an lvalue or a qualifiedid."
$5.3.1/2 - "The result of each of the following unary operators is a
prvalue."
So, in effect you are trying to take the address of an rvalue which is not allowed.
Further, C++ does not allow to return an array.
So, you really want to start looking at what you want. Return the map by value instead is one definite option.
The way I am attempting to solve this problem is by creating the functions as taking an array of void pointers and returning an array of void pointers, and then casting the arguments and return values as needed.
That's (really really) bad. Have a look instead at std::function and std::bind - those should cover differences between function signatures and bound arguments in an elegant way.
The reason I am returning a void** instead of just void* is that there might be a circumstance where I need to return multiple values of different types.
Then return an object that contains the values. For generics have a look at std::tuple or boost::any.
Here's some code:
void function1(int, const char); // defined elsewhere
std::tuple<int,int> function2(std::string&); // defined elsewhere
std::map<std::string,std::function<void(void)>> functionmap;
functionmap.insert( std::make_pair("function1", std::bind(&function1, 2, 'c')) );
std::tuple<int,int> result;
functionmap.insert( std::make_pair("function2", [&result] {
result = function2("this is a test"); } );
// call function1
functionmap["function1"]();
// call function2
functionmap["function2"](); // result will now contain the result
// of calling function2
Is this what you tried to do?
int Foo(int a) { return a; }
typedef int (*FooFunc)(int);
void Bar(){}
typedef std::map<std::string, void*> FunctionMap;
// you should use boost::any or something similar instead of void* here
FunctionMap CreateFunctionMap(const std::string& args)
{
FunctionMap result;
result["Foo"] = &Foo;
result["Bar"] = &Bar;
return result;
}
void Call(FunctionMap::const_reference functionInfo)
{
// #hansmaad The key will give information on the signatures.
// there are a few distinct options, so it will be a conditional
// with a couple of clauses.
if (functionInfo.first == "Foo")
{
auto f = static_cast<FooFunc>(functionInfo.second);
std::cout << f(42);
}
else if (functionInfo.first == "Bar")
{
/* */
}
}
int main()
{
auto functions = CreateFunctionMap("...");
std::for_each(begin(functions), end(functions), Call);
}
#hansmaad The key will give information on the signatures. there are a few distinct options, so it will be a conditional with a couple of clauses. – ewok 33 mins ago
In that case, the typical solution is like this:
typedef void (*func_ptr)();
std::map<std::string, func_ptr> func_map;
map<string,string> string2map(string arg){
//takes a string of the form "key:value;key:value;..." and returns a map<string,string>
map<string, string> result = map <string, string>();
//...
return result;
}
// ...
// Add function to the map
func_map["map<string,string>(string)" = (func_ptr)string2map;
// Call function in the map
std::map<std::string, func_ptr>::iterator it = ...
if (it->first == "map<string,string>(string)")
{
map<string,string> (*func)(string) = (map<string,string>(*)(string))it->second;
map<string,string> result = func("key1;value1;key2;value2");
}
For brevity, I have used C-style casts of the function pointers. The correct C++ cast would be reinterpret_cast<>().
The function pointers are converted to a common type on insertion into the map and converted back to their correct type when invoking them.
I'm learning C++ and can't get my head around this problem:
I have a simple class A
class A {
private:
int ival;
float fval;
public:
A(int i = 0, float f = 0.0) : ival(i), fval(f) { }
~A(){ }
void show() const {
cout << ival << " : " << fval << "\n";
}
void setVal(int i) {
ival = i;
}
//const getters for both ival and fval
//used for the default "lesser"
friend bool operator<(const A& val1, const A& val2) {
return val1.ival < val2.ival ? true : false;;
}
}
Then I have a regular set<A> myset that gets filled with insert(A(2, 2.2)); in a loop.
Iterating to get all the values is not a problem but I want to modify the value within this iteration:
for(set<A>::iterator iter = set3.begin(); iter != set3.end(); iter++) {
iter->setVal(1);
}
I assume that this should be doable, like you would do it in Java within a foreach loop. When compiling I get error: passing ‘const A’ as ‘this’ argument of ‘void A::setVal(int)’ discards qualifiers.
Looking at the sources of the STL set, i see that begin() is only available as a const method and I think this might be the problem. Messing around with const on the setVal() method got always the same error and wouldn't make much sense since I want to modify the value of A.
Is this the wrong approach of changing a bunch of A's values with a loop?
The STL set does not let you change values it stores. It does that by returning a copy of the object through the iterator (not the actual one in the set).
The reason that set does this is because it's using < to order the set and it doesn't want to remake the entire tree every time you dereference the iterator, which it would have to do, since it doesn't know if you changed anything that changes the ordering.
If you need to update the set<>, remove the old value and add in a new one.
EDIT: just checked source to SGI STL and it says this:
typedef typename _Rep_type::const_iterator iterator;
So, a set::iterator is just a set::const_iterator
From this page, it seems that begin() exists as well as a non-const method.
Perhaps your set is passed into the method as a const reference ?
EDIT
The referenced page is wrong. As Scharron states, there is no non-const begin() (or end() for that matter) method for ordered containers.
I will inform the website about their mistake (it's not the first they made ;))