A member of an object is defined as a.b. Is there a way to obtain the member dynamically through a vector? For example:
struct foo{
std::string bar;
};
vector <foo> baz;
baz[0].bar = "0";
Is there a way to access baz.bar while declaring bar? (Example)
void a(std::string b) {
//not sure if this is how it works
std::cout << baz[0].{b};
}
The only way one could use a string to access a member of an object would be like this:
void doStuff(std::string_view m) {
if (m == "bar") {
// Do stuff with bar
} else if (/* other members */) {
// Stuff with other members
}
}
It looks ugly. It is ugly. I wouldn't recommend that.
The reason C++ don't support lookup with strings is because at runtime, there is no information about types, names and any other information about the code itself. The addition of this data into compiled code would only result in memory bloat, and binary bloat, and would be useful in only a selection of code.
There are multiple features that allows similar semantics, but are type safe and faster than strings.
Solution 1: Pointer to members
C++ support pointer to members. They are a variable that can equal to a member of a class. For a given instance, you can access dynamically that member pointed to. Let me give you an example:
// This declares a pointer to member string data of the class foo
std::string foo::* someMember;
// Some member equals to the member bar
someMember = &foo::bar;
// We declare a foo
foo someFoo;
// Direct access to member
std::cout << someFoo.bar << std::endl;
// Access to the member via the pointer to member
std::cout << someFoo.*someMember << std::endl;
The neat thing with that is that you can choose the member at runtime:
// Points to a string member of class foo
std::string foo::* someMember;
if ( someCondition ) {
someMember = &foo::bar;
} else {
// baz is another string member of foo
someMember = &foo::baz;
}
foo someFoo;
// Will either access bar or baz depending on the condition
std::cout << foo.*someMember << std::endl;
The great thing about this is this is type safe. The pointer to member has a definite type of a definite class. This eliminates the problem of having a string equal to not something in your class or something of the wrong type.
If you don't like the syntax to declare a pointer to member, you can always use auto:
// The type of auto is `std::string foo::*`
auto someMember = &foo::bar;
Be aware that the type of someMember is inferred at compile time, and cannot change during program execution.
If I were to rewrite your function a in valid C++, it would look like this:
template<typename MemberType>
void a(MemberType foo::* m) {
std::cout << baz[0].*m;
}
The type MemberType will be inferred at compile-time, just like auto, so your function can work with any type of members. To know more about templates, please refer to your preferred C++ tutorial.
Solution 2: std::unordered_map
Sometimes you really need to lookup thing by strings. You'd like to dynamically declare new member in your class and dynamically access them. In that case, what you need is a map data structure: something that maps a value of some type to another value of some other type.
struct foo {
// We map some strings to some integers
std::unordered_map<std::string, int> values;
};
foo someFoo;
someFoo.values["bar"] = 12;
someFoo.values["baz"] = 15;
// Will print 12, then 15.
std::cout << someFoo.values["bar"] << std::endl;
std::cout << someFoo.values["baz"] << std::endl;
Again, type safety is here: you cannot accidentally assign a double into the map. The lookup type will always be strings and the accociated values will all be ints.
Related
I want to put two (not more) different data types as values into a map as shown in the following example:
typeX A, B, ...;
typeY Z, Y, ...;
void func (typeX) { ... }
void func (typeY) { ... }
std::map <std::string, what_to_put_here??> map;
map["a"] = A;
map["z"] = Z;
...
std::vector<std::string> list;
// This list will be something like "a", "y", ...
for (unsigned int i = 0; i < list.size(); ++i)
func( map[list[i]] )
Obviously this doesn't work, as the map will only accept one data type of value. However, when looping over list, the call to func() should be unambiguous since the type of map[list[i]] is known.
I want to avoid explicit casting or type checking, i.e. something like this:
if (typeid( map[list[i]] ).name() == "typeX")
func( map[list[i]] )
else if (typeid( map[list[i]] ).name() == "typeY")
func( map[list[i]] )
Is this possible? Again, it will be limited to only two different data types.
You want to use boost::variant:
std::map <std::string, boost::variant<typeX, typeY>>
Are typeX and typeY subclasses of a typeBase class ?
If so, you could do a std::map<std::string,typeBase*> to store both typeX* and typeY* in the map.
With some metaprogramming you can easily build an heterogenous map which can store any type from a given set of types. Here is an example which does this, without type erasure nor the need to visit the values.
One way to implement a multi-type map is by using the nifty features of std::tuple in C++11, which allows access by a type key. You can wrap this to create access by arbitrary keys. An in-depth explanation of this (and quite an interesting read) is available here:
https://jguegant.github.io/blogs/tech/thread-safe-multi-type-map.html
If you don't want to use Boost, then I think building a class hierarchy as proposed by rom1504 makes sense. I would implement an abstract base class with func() as member function as follows:
class Base {
public:
virtual void func() = 0;
};
void Base::func() {};
Then, I would turn your typeX and typeY data types into subclasses by deriving from Base as follows:
class typeX : public Base {
public:
void func() { std::cout << "typeX::func()" << std::endl; };
int i; // Example for your original 'typeX' content.
};
class typeY : public Base {
public:
void func() { std::cout << "typeY::func()" << std::endl; };
std::string s; // Example for your original 'typeY' content.
};
Here, the func() implementations would take the content of your corresponding global func() functions. Next, your map needs to store pointers to Base as value:
std::map<std::string, Base*> map;
map["a"] = &A;
map["z"] = &Z;
As a result, you can implement your loop as follows (using a C++11 range-based for loop):
for (auto const &list_item : list)
map[list_item]->func();
Notes:
In case you use dynamically created instances of typeX and typeY, you should prefer to store smart pointers in the map, such as std::unique_ptr or std::shared_ptr, to ease memory management.
If you have to stick to your global func() functions, then you can call them from the corresponding member functions. I would just turn the parameter into a pointer or reference to avoid copying objects.
Full code on Ideone
This would probably be extreme overkill, but QT has a variable called QVariant which can be used to map to different types of (QT) variables.
Documentation here: http://qt-project.org/doc/qt-5.0/qtcore/qvariant.html
You need a type erasure.
Type erasure is a pattern that hides the underlying type, such known examples are boost::any, but keep in mind that boost any has a dynamic polymorphic behavior (dynamic dispatch at runtime). boost::variant on the other hand is another example and uses template metaprogramming techniques. see variant vs any
The simplest solution though, could be writing your own class type erasure with an enum for the underlying type.
In the following program, How do I typecast bar to foo?
#include <iostream>
namespace NA {
class A {
public:
int (*foo)(int);
};
}
namespace NB {
class B : public NA::A {
public:
int bar(int i) {
std::cout << i << std::endl;
return i*2;
}
B() {
this->foo = bar; // how to type cast this fn pointer?
}
};
}
int main() {
NA::A *a = new NB::B();
std::cout << a->foo(2) << std::endl;
}
I tried typecasting as follows but something is going terribly wrong when I run the program:
B() {
typedef int (*TypeFoo)(int);
this->foo = reinterpret_cast<TypeFoo> (&bar);
}
Here's the result when I run:
$ ./a.out
31947824
63895648
I was expecting 2 and 4. How does one typecast the member function pointers above?
Update:
After seeing responses indicating there's no solution to the above problem, I am updating this question further with the specific problem I was trying to address.
Please see https://boringssl.googlesource.com/boringssl/+/HEAD/include/openssl/ssl.h#1173 -- I am trying to have different instances of the struct ssl_private_key_method_st operate on different private keys. I was trying to have another struct inherit from ssl_private_key_method_st and have the sign/decrypt/complete methods operate on instance variables of the inherited struct.
I am aware of using SSL_[sg]et_ex_data to pass data to these functions indirectly, but I was looking for a more simpler / direct way of passing instance data to these functions if possible.
You are running into undefined behavior.
TypeFoo and bar are different types of function pointers (int (*)(int) and int (NB::B::*)(int) respectively).
While it is possible to cast one to the other, using the result to call the function will result in undefined behavior.
8.2.10 Reinterpret cast [expr.reinterpret.cast]
...
6. A function pointer can be explicitly converted to a function pointer of a different type. [ Note: The effect of calling a function through a pointer to a function type (11.3.5) that is not the same as the type used in the definition of the function is undefined. —end note ] Except that converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [ Note: See also 7.11 for more
details of pointer conversions. —end note ]
Short answer: you don't.
Non-static member function pointers are weird. Calling one involves a secret this parameter, and they may or may not be virtual. This makes them impossible to mix with ordinary function pointers.
You should consider using std::function<int(int)> instead of int (*)(int). This would allow you to store something like the following lambda:
B(){
std::function<int(int)> myfn = [this](int x){
return bar(x);
};
}
This lambda captures the current object by reference, and this reference is stored inside the std::function object itself. But you can just as well assign any other function to a std::function, directly or through a lambda or bind expression.
On the other hand, if your bar method doesn't really doesn't depend on an instance, just make it static. This will allow it to mix with regular function pointers, since it no longer needs a secret this and cannot be virtual.
static int bar(int i) {
std::cout << i << std::endl;
return i*2;
}
Written like this, &B::bar can be assigned to a regular int (*)(int) function pointer.
Your TypeFoo defines a pointer to a regular function while bar is a method. Each non-static method has an implicit first parameter this.
So you should decide what do you need: a regular function (in this case make the bar static) or a method, in this case you should typedef like that:
typedef int (B::*TypeFoo)(int);
The reinterpret_cast is an error prone practice. If you cannot cast without it - there is high probability that your code is not correct.
Invoking a member function pointer is a real pain. I suggest you go about this the following way, simplifying much of the context handling:
#include <iostream>
namespace NA {
class A {
public:
int (A::*foo)(int);
};
}
namespace NB {
class B : public NA::A {
public:
int bar(int i) {
std::cout << i << std::endl;
return i*2;
}
int callFoo(int x) {
return (this->*foo)(x);
}
B() {
this->foo = (int(A::*)(int)) (&B::bar);
}
};
}
int main() {
NA::A *a = new NB::B();
std::cout << ((NB::B*)a)->callFoo(2) << std::endl;
}
I want to put two (not more) different data types as values into a map as shown in the following example:
typeX A, B, ...;
typeY Z, Y, ...;
void func (typeX) { ... }
void func (typeY) { ... }
std::map <std::string, what_to_put_here??> map;
map["a"] = A;
map["z"] = Z;
...
std::vector<std::string> list;
// This list will be something like "a", "y", ...
for (unsigned int i = 0; i < list.size(); ++i)
func( map[list[i]] )
Obviously this doesn't work, as the map will only accept one data type of value. However, when looping over list, the call to func() should be unambiguous since the type of map[list[i]] is known.
I want to avoid explicit casting or type checking, i.e. something like this:
if (typeid( map[list[i]] ).name() == "typeX")
func( map[list[i]] )
else if (typeid( map[list[i]] ).name() == "typeY")
func( map[list[i]] )
Is this possible? Again, it will be limited to only two different data types.
You want to use boost::variant:
std::map <std::string, boost::variant<typeX, typeY>>
Are typeX and typeY subclasses of a typeBase class ?
If so, you could do a std::map<std::string,typeBase*> to store both typeX* and typeY* in the map.
With some metaprogramming you can easily build an heterogenous map which can store any type from a given set of types. Here is an example which does this, without type erasure nor the need to visit the values.
One way to implement a multi-type map is by using the nifty features of std::tuple in C++11, which allows access by a type key. You can wrap this to create access by arbitrary keys. An in-depth explanation of this (and quite an interesting read) is available here:
https://jguegant.github.io/blogs/tech/thread-safe-multi-type-map.html
If you don't want to use Boost, then I think building a class hierarchy as proposed by rom1504 makes sense. I would implement an abstract base class with func() as member function as follows:
class Base {
public:
virtual void func() = 0;
};
void Base::func() {};
Then, I would turn your typeX and typeY data types into subclasses by deriving from Base as follows:
class typeX : public Base {
public:
void func() { std::cout << "typeX::func()" << std::endl; };
int i; // Example for your original 'typeX' content.
};
class typeY : public Base {
public:
void func() { std::cout << "typeY::func()" << std::endl; };
std::string s; // Example for your original 'typeY' content.
};
Here, the func() implementations would take the content of your corresponding global func() functions. Next, your map needs to store pointers to Base as value:
std::map<std::string, Base*> map;
map["a"] = &A;
map["z"] = &Z;
As a result, you can implement your loop as follows (using a C++11 range-based for loop):
for (auto const &list_item : list)
map[list_item]->func();
Notes:
In case you use dynamically created instances of typeX and typeY, you should prefer to store smart pointers in the map, such as std::unique_ptr or std::shared_ptr, to ease memory management.
If you have to stick to your global func() functions, then you can call them from the corresponding member functions. I would just turn the parameter into a pointer or reference to avoid copying objects.
Full code on Ideone
This would probably be extreme overkill, but QT has a variable called QVariant which can be used to map to different types of (QT) variables.
Documentation here: http://qt-project.org/doc/qt-5.0/qtcore/qvariant.html
You need a type erasure.
Type erasure is a pattern that hides the underlying type, such known examples are boost::any, but keep in mind that boost any has a dynamic polymorphic behavior (dynamic dispatch at runtime). boost::variant on the other hand is another example and uses template metaprogramming techniques. see variant vs any
The simplest solution though, could be writing your own class type erasure with an enum for the underlying type.
given a struct in the form ( declared before the main() or after )
struct
{
...
} bar;
I don't know how to manage this and how to treat this kind of object.
In general I would like a 360° answer about this but I also have few questions:
is this equivalent to declaring a static struct ?
it's legal and safe in C++11 ?
how to access bar by reference ?
For the last one I have prepared a small snippet here, that doesn't works but shows what I'm trying to achieve.
It's global object of unnamed struct. You cannot use this type as argument to function (since you doesn't know real type of the object). You can use decltype for this, but it doesn't needed since it's global object. It's legal and safe.
#include <iostream>
struct
{
double k1 = 0.123;
} bar;
int foo(decltype(bar)& a)
{
return a.k1-1;
};
int main()
{
std::cout << foo(bar) << std::endl;
return(0);
}
example
Really, since you have only one global object of this struct - you simply can use
#include <iostream>
struct
{
double k1 = 0.123;
} bar;
int foo()
{
return bar.k1-1;
};
int main()
{
std::cout << foo() << std::endl;
return(0);
}
This is simply a global variable. You can access it from any function or method in this compilation unit. The correct way of declaring it (in regard to your snippet) would be:
struct foo
{
double k = 1.23;
};
foo bar;
Now you can simply pass it by reference like this:
void f(foo & b)
{
b.k = 34.5;
}
In your snippet, bar is a variable of type being an unnamed struct:
struct <unnamed>
{
double k = 1.23;
} bar;
Since you did not give any name to your type, you're unable to pass it as a parameter to functions in the classic way. C++11 allows you to do so using the decltype directive:
struct
{
double k = 1.23;
} bar;
void f(decltype(bar) & b)
{
b.k = 3.45;
}
As for your questions:
It is not the same as a static struct. Static variables behave in a little different way. Static classes (= structs) too.
It is legal and safe to use global variables in C++11, but it is strongly advised not to use them, because they may easily break program's logic or architecture. Instead, one should use static classes or singletons.
No. static is a storage attribute. A struct is like any other data type: it can be static, volatile, auto, extern, and others defined by some implementations.
It is legal and safe.
Reference such a structure like this:
struct {
int field1, field2;
double yada, yada2, yada3;
} bar1, bar2;
bar1.yada3 = 3.14159265358979; // assign a field in the struct
bar2 = bar1; // copy contents of bar1 to bar2
1> bar is only single instance of its type. You can not have another instance of same type as bar. Its type is unnamed type struct, just like anonymous union. It is legal to have one such. It is more like global static(but not it is not static) just because you cannot refer it by extern keyword in other file.Any hack you have to refer it in other file ...?
3> It is legal to have it.
4> You can not declare reference to variable whose type you do not know. .Although u can access/modify same object anywhere in the file, so no need of reference. References are used to remove * and -> from code, mainly, otherwise what references do, is all possible with pointer.
is this equivalent to declaring a static struct ?
No, you'd use the static keyword for that, as for any other static variable. It's declaring a global variable, i.e. with static storage duration and external linkage, equivalent to:
struct Bar {...};
Bar bar;
it's legal and safe in C++11 ?
Yes.
how to access bar by reference ?
Since the type has no name, it has to be inferred, either by template argument deduction or, in C++11:
auto & ref = bar;
template <typename Bar> void bar_by_ref(Bar & bar) {
/* do something with bar */
}
Alternatively, in C++11, the type can be extracted by decltype:
decltype(bar) & ref = bar;
For several reasons, I must use a struct defined in an extern C lib. I have simplified my code in order to make it readable.
Struct defined in C Lib
extern "C" {
typedef struct {
double (*_function)(double x);
} FuncR;
}
Cpp file containing class A
Class A {
public:
A();
void foo(double x); // Cannot be static since it uses m
void bar();
private:
double m; // non-static member by nature
};
void A::bar() {
FuncR f;
f._function = &A::foo;
};
The call f._function = &A::foo; generates the following error :
error C2440 : '=' : cannot convert from 'double (__thiscall A::*)(double)' to 'double(__cdecl*)(double)'
I have been searching for answers and apparently foomust be declared static. In my case it is not possible since it has to use non-static members...
Is there any trick to solve my problem ?
No, I don't think there's a trick to "fix" this.
The method call needs a this pointer, which the function pointer can't handle.
Often you can define a static "trampoline" function to get you into a method, but that requires that the outer layers (the C code, in this case) supports passing around e.g. a void * where you can store the this pointer.
Does the FuncR struct really need to be defined/used in C code? Can you use C++-style member function pointers?
How about this?...
class A;
struct classA_MemberFuncR {
double(A::*_function)(double);
};
class A {
public:
A() : m(1.234) {};
double foo(double x) {
std::cout << "In foo(" << x << "): this="
<< (void*)this << ", m=" << m << '\n';
return m+x;
}
void bar();
private:
double m; // non-static member by nature
};
void A::bar() {
classA_MemberFuncR fm;
fm._function = &A::foo;
double result = (this->*fm._function)(4.321);
std::cout << "Result is: " << result << std::endl;
};
[Comment added at this point:] Dang. Re-read OP's original post. (Supposedly we're stuck with the C struct's non-member function pointer.)
Hmm. On GCC I tried a whole lot of casting combinations and it never let me cast M::foo's address to much of anything else, so I wrote a runtime cast function template to force it to allow me to cast anything at all to any other type I want without complaining (Everyone: Please hold off on the screams of "that's not portable!" Sure it's portable... It's just how you use it that may or may not be portable!):
/*---- In a header file somewhere... ----*/
#include <stdarg.h>
template <typename ToTy, typename FromTy>
ToTy forceCast_helper(int dummy, ...);
template <typename ToTy, typename FromTy>
inline ToTy forceCast(FromTy obj) {
// ...has nothing to do with Star Wars!
return forceCast_helper<ToTy,FromTy>(1, obj);
}
/*---- In a source file somewhere... ----*/
template <typename ToTy, typename FromTy>
ToTy forceCast_helper(int dummy, ...) {
va_list args;
va_start(args, dummy);
ToTy ret = va_arg(args, ToTy);
va_end(args);
return ret;
}
Which allowed me to compile the following code without error:
typedef double(*doubleFuncDouble_t)(double);
typedef double(A::*doubleClassAMemberfuncDouble_t)(double);
f._function = forceCast<doubleFuncDouble_t>(&A::foo);
// and then call this->foo(4.321) with it from within A::bar() as follows...
(this->*(forceCast<doubleClassAMemberfuncDouble_t>(f._function)))(4.321);
Unfortunately when it ran, it segfaulted. Further investigation shows that, at least on GCC for 32-bit Linux for x86, sizeof(a member function pointer) is 8, while sizeof(a nonmember function pointer) is 4. When I changed the type of FuncR::_function to uint64_t, amazingly, the call succeeded. (I was surprised as well.)
So it seems regardless of any casting magic you might find that compiles without error, there's really no way at all you'd ever be able to squeeze a member function pointer into a nonmember function pointer, at least on GCC for 32-bit x86. And even if you could, that doesn't encapsulate the 'this' pointer, as 'unwind' mentioned in his post.
I think there's still hope, though.
unwind's post suggests a trampoline function but concedes that it would require separately passing the 'this' pointer & managing that in the C code as a void*. I'm assuming your C library is not modifiable? If so, you should still be able to do a trampoline without being able to pass a 'this' pointer through it, assuming you have a limited number of such function pointers you'll need to be specifying:
You could create an array of class A object pointers, sized to however many of these FuncR function pointer objects you'll be using:
A* arrayThatHoldsAObjPointers[8]; // assuming you only need 8 such FuncR func ptr objects
Then create that many physical static nonmember functions (each conveniently named with a suffix number corresponding with its associated array index), and in the body of each, make them call A::foo() via its associated 'A' object in the arrayThatHoldsAObjPointers:
double trampoline_0(double d) { return arrayThatHoldsAObjPointers[0]->foo(d); }
double trampoline_1(double d) { return arrayThatHoldsAObjPointers[1]->foo(d); }
...and so on...
Then when you need to set a FuncR object for use by your C library, give it the address of one of the trampolines, and at the same time, store the pointer to that A object in the associated arrayThatHoldsAObjPointers[] element. To make the code that sets these easier to use, you could also create an array of function pointers to the trampolines.