I am trying to initialize an std::array of function pointers. These pointers point to member functions of an already instantiated object.
Can somebody please help with the following example? Many thanks in advance!
#include <array>
using TVoidVoid = void (*)(void);
class Foo {
public:
constexpr Foo() {}
void myHandler() {}
};
class Bar {
public:
constexpr Bar() : handler_{nullptr} {}
constexpr Bar(TVoidVoid handler) : handler_{handler} {}
private:
TVoidVoid handler_;
};
Foo f;
std::array<Bar, 5> bar_array = {{Bar{}, Bar{f.myHandler}}};
int main() {}
compiling produces:
main.cpp:22:56: error: no matching function for call to ‘Bar::Bar(<brace-enclosed initializer list>)’
std::array<Bar, 5> bar_array = {{Bar{}, Bar{f.myHandler}}};
I am using g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0.
Pointers to free functions are handled differently than pointers to member functions. The TVoidVoid type is a pointer to a free function, but you need a pointer to a Foo member function. Hence, define Foo first,
class Foo { /* As before... */ };
then go with a type alias for the member function (Foo must be known at this point)
// Note the different syntax to the former TVoidVoid
using FooVoidVoid = void (Foo::*)();
Next, Bar must be adjusted such that its data member is of type FooVoidVoid and the constructor accepts this type as an argument (the rest of Bar can be left as it is), and finally defined the array as
std::array<Bar, 3> bar_array = {{Bar{}, Bar{&Foo::myHandler}}};
Note that &Foo::myHandler has nothing to do with any existing Foo instance. It's just a pointer to a Foo member function, and only when you invoke it, this must be brought together with a Foo object (the special operators .* and ->* are meant for this to happen, or use std::invoke once you upgrade to a C++17-enabled compiler).
Related
I have C++ code that boils down to something like the following:
class Foo{
bool bar;
bool baz;
Foo(const void*);
};
Foo::Foo(const void* ptr){
const struct my_struct* s = complex_method(ptr);
bar = calculate_bar(s);
baz = calculate_baz(s);
}
Semantically, the bar and baz member variables should be const, since they should not change after initialization. However, it seems that in order to make them so, I would need to initialize them in an initialization list rather than assign them. To be clear, I understand why I need to do this. The problem is, I can't seem to find any way to convert the code into an initialization list without doing one of the following undesirable things:
Call complex_method twice (would be bad for performance)
Add the pointer to the Foo class (would make the class size needlessly large)
Is there any way to make the variables const while avoiding these undesirable situations?
If you can afford a C++11 compiler, consider delegating constructors:
class Foo
{
// ...
bool const bar;
bool const baz;
Foo(void const*);
// ...
Foo(my_struct const* s); // Possibly private
};
Foo::Foo(void const* ptr)
: Foo{complex_method(ptr)}
{
}
// ...
Foo::Foo(my_struct const* s)
: bar{calculate_bar(s)}
, baz{calculate_baz(s)}
{
}
As a general advice, be careful declaring your data members as const, because this makes your class impossible to copy-assign and move-assign. If your class is supposed to be used with value semantics, those operations become desirable. If that's not the case, you can disregard this note.
One option is a C++11 delegating constructor, as discussed in other answers. The C++03-compatible method is to use a subobject:
class Foo{
struct subobject {
const bool bar;
const bool baz;
subobject(const struct my_struct* s)
: bar(calculate_bar(s))
, baz(calculate_baz(s))
{}
} subobject;
Foo(const void*);
};
Foo::Foo(const void* ptr)
: subobject(complex_method(ptr))
{}
You can make bar and baz const, or make the subobject const, or both.
If you make only subobject const, then you can calculate complex_method and assign to bar and baz within the constructor of subobject:
class Foo{
const struct subobject {
bool bar;
bool baz;
subobject(const void*);
} subobject;
Foo(const void*);
};
Foo::Foo(const void* ptr)
: subobject(ptr)
{}
Foo::subobject::subobject(const void* ptr){
const struct my_struct* s = complex_method(ptr);
bar = calculate_bar(s);
baz = calculate_baz(s);
}
The reason that you can't mutate const members within a constructor body is that a constructor body is treated just like any other member function body, for consistency. Note that you can move code from a constructor into a member function for refactoring, and the factored-out member function doesn't need any special treatment.
You may use delegate constructor in C++11:
class Foo{
public:
Foo(const void* ptr) : Foo(complex_method(ptr)) {}
private:
Foo(const my_struct* s) : bar(calculate_bar(s)), baz(calculate_baz(s)) {}
private:
const bool bar;
const bool baz;
};
If you don't want to use the newfangled delegating constructors (I still have to deal with compiler versions that don't know about them), and you don't want to change the layout of your class, you could opt for a solution that replaces the constructor with const void * argument by a static member function returning Foo, while having a private constructor that takes the output from complex_method as argument (that latter much like the delegating constructor examples). The static member function then does the necessary preliminary computation involving complex_method, and ends with return Foo(s);. This does require that the class have an accessible copy constructor, even though its call (in the return statement) can most probably be elided.
I am reading C++ programming language by Bjarne Stroustrup. I came across the statement in templates section.
A template argument can be a constant expression (§C.5), the address of an object or function
with external linkage (§9.2), or a non overloaded pointer to member (§15.5).
What is non overloaded pointer to member? Can someone give example?
A non-overloaded pointer-to-member is as the name states -- a pointer to a member that hasn't overloaded a superclass. Here's an example I've just put together of what will and won't work:
#include <iostream>
class Foo {
public:
virtual void printN() { std::cout << 42; }
};
class Bar : public Foo {
public:
void printN() { std::cout << 31; }
};
template <typename T, typename C>
class SomeTemplate {
public:
void PrintData(T d) { C c; (c.*d)(); }
};
int main() {
SomeTemplate<void (Foo::*) (), Foo> t; // Compiles - '42'
t.PrintData(&Foo::printN);
SomeTemplate<void (Bar::*) (), Bar> t; // Compiles - '31'
t.PrintData(&Bar::printN);
SomeTemplate<void (Foo::*) (), Bar> t; // Won't compile, can't convert overloaded pointers
t.PrintData(&Foo::printN);
return 0;
}
In PrintData, an instance of the class is created and the member pointer passed is dereferenced on the instantiated version of the class, resulting in it's underlying function being called.
Templates make this approach somewhat more flexible, but I've yet to find a reason to use code such as this in a real situation however -- if anyone can find a one I'd love to be enlightened..
I'm having difficulties defining a function pointer that can point to any member function (not just member functions for the specified class).
For instance, C++ forces me to specify the class that a function pointer to a member function would point to:
typedef void (Foo::*MyFunctionPointerTypeName)(int);
but what if the class member function that this function pointer is going to point to isn't in Foo? How then would I write this, or what alternative approach could I use?
Update: For anyone looking for a quick answer on how to accomplish this with a C++11 std::function (as tutorials on the subject seem to assume alot of the reader):
Definition (from within Foo):
std::function<void(int)> _fun;
Binding (from any class):
objFoo->_fun = std::bind(&SomeOtherClass::memberFunction,
this, std::placeholders::_1);
Calling it (from within Foo)
if(_fun != nullptr) _fun(42);
If your function has no parameters, you can remove std::placeholders::_1. And if your function has two parameters you'll need to also add std::placeholders::_2 as a parameter to std::bind. Similarly for three parameters, four parameters, etc.
You cannot write a member pointer that could point to a member of any class. Remember: one of the arguments of a member pointer is the class instance itself. And pointers are typed, so the type of its arguments is very much a part of the pointer's type.
You can use std::function however, which can store all sorts of callables. How you would actually call it (ie: what parameters you give it) depends on your needs, as you haven't explained what you're trying to do.
Use inheritance:
#include <iostream>
struct Foo {};
struct Bar : public Foo
{
int F0()
{
return 0;
}
};
struct Baz : public Foo
{
int F1()
{
return 1;
}
};
int main(int argc, char **argv)
{
int (Bar::*pF0)() = &Bar::F0;
int (Baz::*pF1)() = &Baz::F1;
int (Foo::*pointer1)() = static_cast<int (Foo::*)()>(pF0);
int (Foo::*pointer2)() = static_cast<int (Foo::*)()>(pF1);
Bar r;
Baz z;
// Pointer to Foo member function calling Bar member function
std::cout << (r.*pointer1)() << '\n';
// Pointer to Foo member function calling Baz member function
std::cout << (z.*pointer2)() << '\n';
return 0;
}
Output:
0
1
Hope it helps.
I am a bit puzzled about this. When default stack allocated object construction is allowed as member varaiable of other struct, why not parameterized construction ? Does Most Vexing Parse has anything to do with this ? I tried on C++0X as well at ideone and got the same result.
struct foo{
foo() {}
foo(int i) {}
};
struct bar{
foo obj; // Allowed
foo obj2(10); // Not Allowed
};
Error: expected ‘,’ or ‘...’ before numeric constant
IdeOne Demo
Your link to Most Vexing Parse discusses instantiation of non-member variables (variables which are not a member of a class/struct). The example you've shown is that of member variables being declared in a struct; for which you would typically initialise them in a constructor
struct bar
{
foo obj;
foo obj2;
bar() : obj2(10) {}
};
The Most Vexing Parse problem occurs in situations such as the below:
struct baz
{
baz(int n) {}
};
void foo()
{
baz meow(int());
}
where the identifier meow appears to be a function declaration of type baz (int), due to the 'most vexing parse' issues described in your link. (the int() which at first glance appears to be default-initialisation actually turns out to be simply the data type int)
write
struct bar {
foo obj;
foo obj2;
foo(): obj2(10) {}
}
This way, when instantiating bar, obj2 construction will be made with 10.
Prior to C++11, you couldn't initialize members in the declaration unless they were static const and integral.
In C++11, you can use uniform initialization and in-class member initializtion:
foo obj2{10};
Since the constructor is not explicit, you can also do this:
foo obj2 = 10;
Not in C++11, you have to use a member initializer in the constructor list.
Suppose I have a class Baz that inherits from classes Foo and Bar, in that order. The constructor for class Bar takes a pointer to a Foo object. What I would like to do is to pass this as the Foo object to the Bar constructor:
Baz () : Foo(), Bar(this) {}
A working example:
#include <iostream>
class Bar;
class Foo {
public:
virtual ~Foo() {}
virtual void parse_bar (Bar&) const = 0;
};
class Bar {
private:
const Foo * parser;
public:
Bar (const Foo * parser_in) : parser(parser_in) {}
virtual ~Bar() {}
void parse_self () { parser->parse_bar (*this); }
};
class Baz : public Foo, public Bar {
public:
Baz () : Foo(), Bar(this) {}
virtual void parse_bar (Bar &) const { std::cout << "Hello World\n"; }
};
int main () {
Baz baz;
baz.parse_self();
}
This happens to work on my computer, with my compilers (tested with a couple of them). However section 9.3.2 of the 2003 standard makes me a bit uneasy that I might just be getting lucky, that using this this way is undefined behavior. Strictly speaking, the initializer list is outside the body of the constructor. Here's the relevant text, emphasis mine:
9.3.2 The this pointer
In the body of a nonstatic member function, the keyword this is a non-lvalue expression whose value is the address of the object for which the function is called.
So is my usage legal and well-defined, or is it undefined behavior?
There are two points that have to be noted in this case.
Firstly, in the constructor initializer list this pointer refers to a non-constructed (or not-fully-constructed) object. It is OK to access such pointer, but the object it refers to can only be used in limited ways. See 12.7 in the language specification.
Secondly, in your specific example what you are actually doing is converting this pointer to Foo * type before attempting any access. This is completely safe since by that moment the Foo subobject is fully constructed. (I assume that, whatever access will follow, if any, will be restricted only to the fully constructed Foo subobject).
The only concern is this case is whether it is legal to convert this to Foo * type, i.e. whether the conversion process itself should succeed. The answer is: yes, in case of ordinary (non-virtual) inheritance such conversion is perfectly legal and safe (again, explicitly allowed in 12.7)
It is fine. The C++ standard actually clarifies the use of this pointers in initializer lists:
12.6.2 Initializing bases and members [class.base.init]
Paragraph 7: Names in the expression-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified. [Example:
class X {
int a;
int b;
int i;
int j;
public:
const int& r;
X(int i): r(a), b(i), i(i), j(this->i) {}
};
initializes X::r to refer to X::a, initializes X::b with the
value of the constructor parameter i, initializes X::i with the
value of the constructor parameter i, and initializes X::j with
the value of X::i; this takes place each time an object of class X
is created. ] [Note: because the mem-initializer are evaluated in
the scope of the constructor, the this pointer can be used in the
expression-list of a mem-initializer to refer to the object being
initialized. ]
The type of the this pointer in the initializer of Baz is in fact of type Baz. Of course, you have to be mindful of the fact that not all of the members may have been initialized. Many, if not all, compilers set at their highest warning levels (which you really should be doing anyway) will warn about you passing a this pointer to the base class.
However, it looks like you're making it more complicated that it needs to be. Why not just put the virtual function parse_bar() in the Bar class, and forget about the Foo class?
#include <iostream>
class Bar
{
public:
Bar() {}
virtual ~Bar() {}
void parse_self () { parse_bar(); }
private: // Template method pattern
virtual void parse_bar() const = 0;
};
class Baz : public Bar
{
public:
Baz () {}
private: // Yes, this does override the private `parse_bar()` member!
virtual void parse_bar() const { std::cout << "Hello World\n"; }
};
int main ()
{
Baz baz;
baz.parse_self();
}
This does essentially the same function but with less code.