How do I create an array of function pointers of different prototypes?
up vote
27
down vote
favorite
I have a few functions defined like this:
ParentClass* fun1();
ParentClass* fun2();
ParentClass* fun3(bool inp=false);
ChildClass* fun4();
ChildClass* fun5(int a=1, int b=3);
I would like to put them into an array of some kind as follows:
void* (*arr[5])() = {
(void* (*)())fun1,
(void* (*)())fun2,
(void* (*)())fun3,
(void* (*)())fun4,
(void* (*)())fun5
}
Now I would like to use this array of functions simply as
for(int i=0; i<5; i++)
someFunction(arr[i]());
Now I realize here that the issue is void* (*arr[5])()
, but given that I only want to use the functions without supplying an argument, I would like all of these to be part of the same array.
These are very C-style ways to do it, though. Is there a better way to do it using Templates in C++?
c++ function oop c++14
add a comment |
up vote
27
down vote
favorite
I have a few functions defined like this:
ParentClass* fun1();
ParentClass* fun2();
ParentClass* fun3(bool inp=false);
ChildClass* fun4();
ChildClass* fun5(int a=1, int b=3);
I would like to put them into an array of some kind as follows:
void* (*arr[5])() = {
(void* (*)())fun1,
(void* (*)())fun2,
(void* (*)())fun3,
(void* (*)())fun4,
(void* (*)())fun5
}
Now I would like to use this array of functions simply as
for(int i=0; i<5; i++)
someFunction(arr[i]());
Now I realize here that the issue is void* (*arr[5])()
, but given that I only want to use the functions without supplying an argument, I would like all of these to be part of the same array.
These are very C-style ways to do it, though. Is there a better way to do it using Templates in C++?
c++ function oop c++14
Why do you want to discard the type from the return? doesChildClass
not inheritParentClass
?
– Caleth
Dec 5 at 9:47
When I use it, I am actually casting it toParentClass
. I could make this a ParentClass* instead of void*, but that way I would have to type cast each entry into the array. I instead currently choose to cast it after I retrieve it from the array.
– vc669
Dec 5 at 10:00
I miscommunicated through the question that I didn't want to use. I do want to use it. Modified the question accordingly.
– vc669
Dec 5 at 10:32
In your first snippet you have declaredfun4
twice, is that a typo?
– Fabio Turati
Dec 5 at 13:48
Yup. Corrected.
– vc669
Dec 5 at 17:16
add a comment |
up vote
27
down vote
favorite
up vote
27
down vote
favorite
I have a few functions defined like this:
ParentClass* fun1();
ParentClass* fun2();
ParentClass* fun3(bool inp=false);
ChildClass* fun4();
ChildClass* fun5(int a=1, int b=3);
I would like to put them into an array of some kind as follows:
void* (*arr[5])() = {
(void* (*)())fun1,
(void* (*)())fun2,
(void* (*)())fun3,
(void* (*)())fun4,
(void* (*)())fun5
}
Now I would like to use this array of functions simply as
for(int i=0; i<5; i++)
someFunction(arr[i]());
Now I realize here that the issue is void* (*arr[5])()
, but given that I only want to use the functions without supplying an argument, I would like all of these to be part of the same array.
These are very C-style ways to do it, though. Is there a better way to do it using Templates in C++?
c++ function oop c++14
I have a few functions defined like this:
ParentClass* fun1();
ParentClass* fun2();
ParentClass* fun3(bool inp=false);
ChildClass* fun4();
ChildClass* fun5(int a=1, int b=3);
I would like to put them into an array of some kind as follows:
void* (*arr[5])() = {
(void* (*)())fun1,
(void* (*)())fun2,
(void* (*)())fun3,
(void* (*)())fun4,
(void* (*)())fun5
}
Now I would like to use this array of functions simply as
for(int i=0; i<5; i++)
someFunction(arr[i]());
Now I realize here that the issue is void* (*arr[5])()
, but given that I only want to use the functions without supplying an argument, I would like all of these to be part of the same array.
These are very C-style ways to do it, though. Is there a better way to do it using Templates in C++?
c++ function oop c++14
c++ function oop c++14
edited Dec 5 at 17:15
asked Dec 5 at 9:15
vc669
31628
31628
Why do you want to discard the type from the return? doesChildClass
not inheritParentClass
?
– Caleth
Dec 5 at 9:47
When I use it, I am actually casting it toParentClass
. I could make this a ParentClass* instead of void*, but that way I would have to type cast each entry into the array. I instead currently choose to cast it after I retrieve it from the array.
– vc669
Dec 5 at 10:00
I miscommunicated through the question that I didn't want to use. I do want to use it. Modified the question accordingly.
– vc669
Dec 5 at 10:32
In your first snippet you have declaredfun4
twice, is that a typo?
– Fabio Turati
Dec 5 at 13:48
Yup. Corrected.
– vc669
Dec 5 at 17:16
add a comment |
Why do you want to discard the type from the return? doesChildClass
not inheritParentClass
?
– Caleth
Dec 5 at 9:47
When I use it, I am actually casting it toParentClass
. I could make this a ParentClass* instead of void*, but that way I would have to type cast each entry into the array. I instead currently choose to cast it after I retrieve it from the array.
– vc669
Dec 5 at 10:00
I miscommunicated through the question that I didn't want to use. I do want to use it. Modified the question accordingly.
– vc669
Dec 5 at 10:32
In your first snippet you have declaredfun4
twice, is that a typo?
– Fabio Turati
Dec 5 at 13:48
Yup. Corrected.
– vc669
Dec 5 at 17:16
Why do you want to discard the type from the return? does
ChildClass
not inherit ParentClass
?– Caleth
Dec 5 at 9:47
Why do you want to discard the type from the return? does
ChildClass
not inherit ParentClass
?– Caleth
Dec 5 at 9:47
When I use it, I am actually casting it to
ParentClass
. I could make this a ParentClass* instead of void*, but that way I would have to type cast each entry into the array. I instead currently choose to cast it after I retrieve it from the array.– vc669
Dec 5 at 10:00
When I use it, I am actually casting it to
ParentClass
. I could make this a ParentClass* instead of void*, but that way I would have to type cast each entry into the array. I instead currently choose to cast it after I retrieve it from the array.– vc669
Dec 5 at 10:00
I miscommunicated through the question that I didn't want to use. I do want to use it. Modified the question accordingly.
– vc669
Dec 5 at 10:32
I miscommunicated through the question that I didn't want to use. I do want to use it. Modified the question accordingly.
– vc669
Dec 5 at 10:32
In your first snippet you have declared
fun4
twice, is that a typo?– Fabio Turati
Dec 5 at 13:48
In your first snippet you have declared
fun4
twice, is that a typo?– Fabio Turati
Dec 5 at 13:48
Yup. Corrected.
– vc669
Dec 5 at 17:16
Yup. Corrected.
– vc669
Dec 5 at 17:16
add a comment |
5 Answers
5
active
oldest
votes
up vote
40
down vote
accepted
C-style or not, what you have is straight undefined behaviour. Use lambdas:
void (*arr[5])() = {
{ fun1(); },
{ fun2(); },
{ fun3(); },
{ fun4(); },
{ fun5(); }
};
These are okay because they perform the call through the function's correct type, and are themselves convertible to void (*)()
.
Forwarding the returned value stays simple enough, since the lambda provides a context for the conversion. In your case, since ChildClass
supposedly inherits from ParentClass
, an implicit conversion is enough:
ParentClass *(*arr[5])() = {
() -> ParentClass * { return fun1(); },
() -> ParentClass * { return fun2(); },
() -> ParentClass * { return fun3(); },
() -> ParentClass * { return fun4(); },
() -> ParentClass * { return fun5(); }
};
Does this make the return type of the functionsvoid
?
– vc669
Dec 5 at 10:14
@vc669 Yes, since you don't use it anyway. However, you can also use the lambdas to reconcile the return types, which since I guessChildClass
inherits fromParentClass
is just() -> ParentClasss * { return fun1(); }
.
– Quentin
Dec 5 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 at 12:08
1
@Aconcagua yes, but consistency. One could avoid repetition by using a function that takes in all of thefun*
's at once and returns the array of wrapped functions as well.
– Quentin
Dec 5 at 12:18
1
@Aconcagua Almost: it gets compiled into a singlejmp
. Although the function's body will be inlined into the lambda if applicable.
– Quentin
Dec 5 at 12:33
|
show 2 more comments
up vote
15
down vote
but given that I only want to use the functions without supplying an argument
It simply doesn't work like that. Did you ever wonder, then when you're put function declarations in a header, why you have to write default parameters into the header and can not place it in the definition in the implementation source file?
That's because the default parameters are in fact not "embedded" into the function, but used by the compiler to augment a function call with those parameters at a calling location, where those parameters are omitted. (EDIT: Also, as @Aconcagua so keenly observed in a comment, since default parameters are usually defined as part of a header function declaration, any change of the default values requires a full recompilation of any compilation unit that included those headers, ergo function declarations, for the change to actually take effect!)
While it's perfectly possible to do some really weird type casting madness to construct an array of function pointers like that, eventually you'll have to cast back to the original function call signature in order to not invoke undefined behavior.
If anything you'll have to bind the function pointer, together with a set of default parameters in some type that abstracts away the calling, does supply the parameters and to the outside offers a polymorphic interface. So you'd have a std::vector<function_binder>
or function_binder
where function binder has a operator()
that calls the function.
But when you're doing binding in the first place, you can bind it in an anonymous function, i.e. lambdas. At the time of lambda instanciation the default parameters are bound.
std::vector<void(*)()> fvec = {
{ func0(); },
{ func1(); },
{ func2(); },
}
Might be worth to mention that, as parameters are provided in header, if changing these, any translation units relying on need to be re-compiled to make these changes effective there as well...
– Aconcagua
Dec 5 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 at 12:55
add a comment |
up vote
9
down vote
You can use std::bind
std::function<ParentClass *(void)> arr[5] = {
std::bind(&fun1),
std::bind(&fun2),
std::bind(&fun3, false),
std::bind(&fun4),
std::bind(&fun5, 1, 3)
};
now you can do
for(int i=0; i<5; i++)
arr[i]();
You have to make sure every function parameter of all functions are bound.
This also works well with member functions. You just have to bind the object reference (e.g. this
) as first parameter.
1
since C++11 and above there is no point to usebind
since lambda is more handy and faster.
– Marek R
Dec 5 at 9:42
@Marek R - Depending on implementationstd::bind
might just return an lambda because it's return type is unspecified. It's probably just a matter of taste which one you use.
– Detonar
Dec 5 at 9:47
2
My taste saysstd::bind
since if forces less disciplined developer to write small functions. Lambda is often overused and grows to ridicules sizes, but still it is easier to use and it is faster.std::bind
creates complex templates which is annoying when analyzing a crash logs.
– Marek R
Dec 5 at 9:51
This does not compile.
– Quentin
Dec 5 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 at 10:08
|
show 4 more comments
up vote
3
down vote
A c++20 solution:
#define RETURNS(...)
noexcept(noexcept(__VA_ARGS__))
-> decltype(__VA_ARGS__)
{ return __VA_ARGS__; }
template<auto f, class R, class...Args>
struct explicit_function_caster {
using Sig=R(Args...);
using pSig=Sig*;
constexpr operator pSig()const {
return (Args...args)->R {
return static_cast<R>(f(std::forward<Args>(args)...));
};
}
};
template<auto f>
struct overload_storer_t {
template<class R, class...Args>
constexpr (*operator R() const)(Args...) const {
return explicit_function_caster<f, R, Args...>{};
}
template<class...Args>
auto operator()(Args&&...args)
RETURNS( f( std::forward<Args>(args)... ) )
};
template<auto f>
overload_storer_t<f> generate_overloads={};
#define OVERLOADS_OF(...)
generate_overloads<
(auto&&...args)
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
>
which is a lot of boilerplate, but gets us:
ParentClass* (*arr[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
void (*arr2[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
basically generate_overloads<x>
takes a constexpr
callable object x
and lets you cast it at compile time to a pointer to a function of any compatible signature and call it with (almost) any signature.
Meanwhile, OVERLOADS_OF
converts a function name into a constexpr
object that does overload resolution on that function name. I use it here because fun3
as a function pointer does not know about its default arguments, but at overload resolution time it does.
In this particular case, it is far easier to just write toy lambdas to do this work; this is just an attempt to automate writing those toy lambdas for arbitrary compatible signatures.
constexpr (*operator R() const)(Args...) const
oh what the hell... Also, isdecltype(args)(args)...
a replacement forstd::forward
or is there additional subtlety?
– Quentin
Dec 5 at 20:56
@Quentin Yes. I don't have the type ofargs
. The cast operator was there because the C++2a compilers didn't likeauto
based partial specialization, so I couldn't easily unpack aSig
: that is a type-deduced conversion operator to function pointer.
– Yakk - Adam Nevraumont
Dec 5 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 at 21:41
1
@Quentin Laugh, I think I converted to a const function pointer in a const method. Accidentally: the fact the function pointer is const is pointless.
– Yakk - Adam Nevraumont
Dec 5 at 22:04
add a comment |
up vote
1
down vote
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function
and lambadas.
Also you should not use C style array, but only std::array
and/or std::vector
.
Also avoid raw pointers, use std::unique_ptr
and std::shared_ptr
.
So simplest and best whay to solve it is:
std::array<std::function<ParentClass*()>,5> arr {
() { return fun1(); },
() { return fun2(); },
() { return fun3(true); },
() { return fun4(); },
() { return fun5(7, 9); }
};
Why not simple array of pointers like in @Quentin answer? He used lambdas, but he can't use lambda which binds anything (if you need to).
2
Downvoted becausestd::function
is a heavyweight facility, and the problem at hand does not require any of the functionality it provides over plain function pointers.
– Quentin
Dec 5 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 at 10:08
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53628791%2fhow-do-i-create-an-array-of-function-pointers-of-different-prototypes%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
40
down vote
accepted
C-style or not, what you have is straight undefined behaviour. Use lambdas:
void (*arr[5])() = {
{ fun1(); },
{ fun2(); },
{ fun3(); },
{ fun4(); },
{ fun5(); }
};
These are okay because they perform the call through the function's correct type, and are themselves convertible to void (*)()
.
Forwarding the returned value stays simple enough, since the lambda provides a context for the conversion. In your case, since ChildClass
supposedly inherits from ParentClass
, an implicit conversion is enough:
ParentClass *(*arr[5])() = {
() -> ParentClass * { return fun1(); },
() -> ParentClass * { return fun2(); },
() -> ParentClass * { return fun3(); },
() -> ParentClass * { return fun4(); },
() -> ParentClass * { return fun5(); }
};
Does this make the return type of the functionsvoid
?
– vc669
Dec 5 at 10:14
@vc669 Yes, since you don't use it anyway. However, you can also use the lambdas to reconcile the return types, which since I guessChildClass
inherits fromParentClass
is just() -> ParentClasss * { return fun1(); }
.
– Quentin
Dec 5 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 at 12:08
1
@Aconcagua yes, but consistency. One could avoid repetition by using a function that takes in all of thefun*
's at once and returns the array of wrapped functions as well.
– Quentin
Dec 5 at 12:18
1
@Aconcagua Almost: it gets compiled into a singlejmp
. Although the function's body will be inlined into the lambda if applicable.
– Quentin
Dec 5 at 12:33
|
show 2 more comments
up vote
40
down vote
accepted
C-style or not, what you have is straight undefined behaviour. Use lambdas:
void (*arr[5])() = {
{ fun1(); },
{ fun2(); },
{ fun3(); },
{ fun4(); },
{ fun5(); }
};
These are okay because they perform the call through the function's correct type, and are themselves convertible to void (*)()
.
Forwarding the returned value stays simple enough, since the lambda provides a context for the conversion. In your case, since ChildClass
supposedly inherits from ParentClass
, an implicit conversion is enough:
ParentClass *(*arr[5])() = {
() -> ParentClass * { return fun1(); },
() -> ParentClass * { return fun2(); },
() -> ParentClass * { return fun3(); },
() -> ParentClass * { return fun4(); },
() -> ParentClass * { return fun5(); }
};
Does this make the return type of the functionsvoid
?
– vc669
Dec 5 at 10:14
@vc669 Yes, since you don't use it anyway. However, you can also use the lambdas to reconcile the return types, which since I guessChildClass
inherits fromParentClass
is just() -> ParentClasss * { return fun1(); }
.
– Quentin
Dec 5 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 at 12:08
1
@Aconcagua yes, but consistency. One could avoid repetition by using a function that takes in all of thefun*
's at once and returns the array of wrapped functions as well.
– Quentin
Dec 5 at 12:18
1
@Aconcagua Almost: it gets compiled into a singlejmp
. Although the function's body will be inlined into the lambda if applicable.
– Quentin
Dec 5 at 12:33
|
show 2 more comments
up vote
40
down vote
accepted
up vote
40
down vote
accepted
C-style or not, what you have is straight undefined behaviour. Use lambdas:
void (*arr[5])() = {
{ fun1(); },
{ fun2(); },
{ fun3(); },
{ fun4(); },
{ fun5(); }
};
These are okay because they perform the call through the function's correct type, and are themselves convertible to void (*)()
.
Forwarding the returned value stays simple enough, since the lambda provides a context for the conversion. In your case, since ChildClass
supposedly inherits from ParentClass
, an implicit conversion is enough:
ParentClass *(*arr[5])() = {
() -> ParentClass * { return fun1(); },
() -> ParentClass * { return fun2(); },
() -> ParentClass * { return fun3(); },
() -> ParentClass * { return fun4(); },
() -> ParentClass * { return fun5(); }
};
C-style or not, what you have is straight undefined behaviour. Use lambdas:
void (*arr[5])() = {
{ fun1(); },
{ fun2(); },
{ fun3(); },
{ fun4(); },
{ fun5(); }
};
These are okay because they perform the call through the function's correct type, and are themselves convertible to void (*)()
.
Forwarding the returned value stays simple enough, since the lambda provides a context for the conversion. In your case, since ChildClass
supposedly inherits from ParentClass
, an implicit conversion is enough:
ParentClass *(*arr[5])() = {
() -> ParentClass * { return fun1(); },
() -> ParentClass * { return fun2(); },
() -> ParentClass * { return fun3(); },
() -> ParentClass * { return fun4(); },
() -> ParentClass * { return fun5(); }
};
edited Dec 5 at 10:34
answered Dec 5 at 9:18
Quentin
44.3k584140
44.3k584140
Does this make the return type of the functionsvoid
?
– vc669
Dec 5 at 10:14
@vc669 Yes, since you don't use it anyway. However, you can also use the lambdas to reconcile the return types, which since I guessChildClass
inherits fromParentClass
is just() -> ParentClasss * { return fun1(); }
.
– Quentin
Dec 5 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 at 12:08
1
@Aconcagua yes, but consistency. One could avoid repetition by using a function that takes in all of thefun*
's at once and returns the array of wrapped functions as well.
– Quentin
Dec 5 at 12:18
1
@Aconcagua Almost: it gets compiled into a singlejmp
. Although the function's body will be inlined into the lambda if applicable.
– Quentin
Dec 5 at 12:33
|
show 2 more comments
Does this make the return type of the functionsvoid
?
– vc669
Dec 5 at 10:14
@vc669 Yes, since you don't use it anyway. However, you can also use the lambdas to reconcile the return types, which since I guessChildClass
inherits fromParentClass
is just() -> ParentClasss * { return fun1(); }
.
– Quentin
Dec 5 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 at 12:08
1
@Aconcagua yes, but consistency. One could avoid repetition by using a function that takes in all of thefun*
's at once and returns the array of wrapped functions as well.
– Quentin
Dec 5 at 12:18
1
@Aconcagua Almost: it gets compiled into a singlejmp
. Although the function's body will be inlined into the lambda if applicable.
– Quentin
Dec 5 at 12:33
Does this make the return type of the functions
void
?– vc669
Dec 5 at 10:14
Does this make the return type of the functions
void
?– vc669
Dec 5 at 10:14
@vc669 Yes, since you don't use it anyway. However, you can also use the lambdas to reconcile the return types, which since I guess
ChildClass
inherits from ParentClass
is just () -> ParentClasss * { return fun1(); }
.– Quentin
Dec 5 at 10:18
@vc669 Yes, since you don't use it anyway. However, you can also use the lambdas to reconcile the return types, which since I guess
ChildClass
inherits from ParentClass
is just () -> ParentClasss * { return fun1(); }
.– Quentin
Dec 5 at 10:18
1
1
Actually, one would only need lambdas for
fun3
and fun5
...– Aconcagua
Dec 5 at 12:08
Actually, one would only need lambdas for
fun3
and fun5
...– Aconcagua
Dec 5 at 12:08
1
1
@Aconcagua yes, but consistency. One could avoid repetition by using a function that takes in all of the
fun*
's at once and returns the array of wrapped functions as well.– Quentin
Dec 5 at 12:18
@Aconcagua yes, but consistency. One could avoid repetition by using a function that takes in all of the
fun*
's at once and returns the array of wrapped functions as well.– Quentin
Dec 5 at 12:18
1
1
@Aconcagua Almost: it gets compiled into a single
jmp
. Although the function's body will be inlined into the lambda if applicable.– Quentin
Dec 5 at 12:33
@Aconcagua Almost: it gets compiled into a single
jmp
. Although the function's body will be inlined into the lambda if applicable.– Quentin
Dec 5 at 12:33
|
show 2 more comments
up vote
15
down vote
but given that I only want to use the functions without supplying an argument
It simply doesn't work like that. Did you ever wonder, then when you're put function declarations in a header, why you have to write default parameters into the header and can not place it in the definition in the implementation source file?
That's because the default parameters are in fact not "embedded" into the function, but used by the compiler to augment a function call with those parameters at a calling location, where those parameters are omitted. (EDIT: Also, as @Aconcagua so keenly observed in a comment, since default parameters are usually defined as part of a header function declaration, any change of the default values requires a full recompilation of any compilation unit that included those headers, ergo function declarations, for the change to actually take effect!)
While it's perfectly possible to do some really weird type casting madness to construct an array of function pointers like that, eventually you'll have to cast back to the original function call signature in order to not invoke undefined behavior.
If anything you'll have to bind the function pointer, together with a set of default parameters in some type that abstracts away the calling, does supply the parameters and to the outside offers a polymorphic interface. So you'd have a std::vector<function_binder>
or function_binder
where function binder has a operator()
that calls the function.
But when you're doing binding in the first place, you can bind it in an anonymous function, i.e. lambdas. At the time of lambda instanciation the default parameters are bound.
std::vector<void(*)()> fvec = {
{ func0(); },
{ func1(); },
{ func2(); },
}
Might be worth to mention that, as parameters are provided in header, if changing these, any translation units relying on need to be re-compiled to make these changes effective there as well...
– Aconcagua
Dec 5 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 at 12:55
add a comment |
up vote
15
down vote
but given that I only want to use the functions without supplying an argument
It simply doesn't work like that. Did you ever wonder, then when you're put function declarations in a header, why you have to write default parameters into the header and can not place it in the definition in the implementation source file?
That's because the default parameters are in fact not "embedded" into the function, but used by the compiler to augment a function call with those parameters at a calling location, where those parameters are omitted. (EDIT: Also, as @Aconcagua so keenly observed in a comment, since default parameters are usually defined as part of a header function declaration, any change of the default values requires a full recompilation of any compilation unit that included those headers, ergo function declarations, for the change to actually take effect!)
While it's perfectly possible to do some really weird type casting madness to construct an array of function pointers like that, eventually you'll have to cast back to the original function call signature in order to not invoke undefined behavior.
If anything you'll have to bind the function pointer, together with a set of default parameters in some type that abstracts away the calling, does supply the parameters and to the outside offers a polymorphic interface. So you'd have a std::vector<function_binder>
or function_binder
where function binder has a operator()
that calls the function.
But when you're doing binding in the first place, you can bind it in an anonymous function, i.e. lambdas. At the time of lambda instanciation the default parameters are bound.
std::vector<void(*)()> fvec = {
{ func0(); },
{ func1(); },
{ func2(); },
}
Might be worth to mention that, as parameters are provided in header, if changing these, any translation units relying on need to be re-compiled to make these changes effective there as well...
– Aconcagua
Dec 5 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 at 12:55
add a comment |
up vote
15
down vote
up vote
15
down vote
but given that I only want to use the functions without supplying an argument
It simply doesn't work like that. Did you ever wonder, then when you're put function declarations in a header, why you have to write default parameters into the header and can not place it in the definition in the implementation source file?
That's because the default parameters are in fact not "embedded" into the function, but used by the compiler to augment a function call with those parameters at a calling location, where those parameters are omitted. (EDIT: Also, as @Aconcagua so keenly observed in a comment, since default parameters are usually defined as part of a header function declaration, any change of the default values requires a full recompilation of any compilation unit that included those headers, ergo function declarations, for the change to actually take effect!)
While it's perfectly possible to do some really weird type casting madness to construct an array of function pointers like that, eventually you'll have to cast back to the original function call signature in order to not invoke undefined behavior.
If anything you'll have to bind the function pointer, together with a set of default parameters in some type that abstracts away the calling, does supply the parameters and to the outside offers a polymorphic interface. So you'd have a std::vector<function_binder>
or function_binder
where function binder has a operator()
that calls the function.
But when you're doing binding in the first place, you can bind it in an anonymous function, i.e. lambdas. At the time of lambda instanciation the default parameters are bound.
std::vector<void(*)()> fvec = {
{ func0(); },
{ func1(); },
{ func2(); },
}
but given that I only want to use the functions without supplying an argument
It simply doesn't work like that. Did you ever wonder, then when you're put function declarations in a header, why you have to write default parameters into the header and can not place it in the definition in the implementation source file?
That's because the default parameters are in fact not "embedded" into the function, but used by the compiler to augment a function call with those parameters at a calling location, where those parameters are omitted. (EDIT: Also, as @Aconcagua so keenly observed in a comment, since default parameters are usually defined as part of a header function declaration, any change of the default values requires a full recompilation of any compilation unit that included those headers, ergo function declarations, for the change to actually take effect!)
While it's perfectly possible to do some really weird type casting madness to construct an array of function pointers like that, eventually you'll have to cast back to the original function call signature in order to not invoke undefined behavior.
If anything you'll have to bind the function pointer, together with a set of default parameters in some type that abstracts away the calling, does supply the parameters and to the outside offers a polymorphic interface. So you'd have a std::vector<function_binder>
or function_binder
where function binder has a operator()
that calls the function.
But when you're doing binding in the first place, you can bind it in an anonymous function, i.e. lambdas. At the time of lambda instanciation the default parameters are bound.
std::vector<void(*)()> fvec = {
{ func0(); },
{ func1(); },
{ func2(); },
}
edited Dec 5 at 12:58
answered Dec 5 at 9:28
datenwolf
131k10129233
131k10129233
Might be worth to mention that, as parameters are provided in header, if changing these, any translation units relying on need to be re-compiled to make these changes effective there as well...
– Aconcagua
Dec 5 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 at 12:55
add a comment |
Might be worth to mention that, as parameters are provided in header, if changing these, any translation units relying on need to be re-compiled to make these changes effective there as well...
– Aconcagua
Dec 5 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 at 12:55
Might be worth to mention that, as parameters are provided in header, if changing these, any translation units relying on need to be re-compiled to make these changes effective there as well...
– Aconcagua
Dec 5 at 12:13
Might be worth to mention that, as parameters are provided in header, if changing these, any translation units relying on need to be re-compiled to make these changes effective there as well...
– Aconcagua
Dec 5 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 at 12:55
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 at 12:55
add a comment |
up vote
9
down vote
You can use std::bind
std::function<ParentClass *(void)> arr[5] = {
std::bind(&fun1),
std::bind(&fun2),
std::bind(&fun3, false),
std::bind(&fun4),
std::bind(&fun5, 1, 3)
};
now you can do
for(int i=0; i<5; i++)
arr[i]();
You have to make sure every function parameter of all functions are bound.
This also works well with member functions. You just have to bind the object reference (e.g. this
) as first parameter.
1
since C++11 and above there is no point to usebind
since lambda is more handy and faster.
– Marek R
Dec 5 at 9:42
@Marek R - Depending on implementationstd::bind
might just return an lambda because it's return type is unspecified. It's probably just a matter of taste which one you use.
– Detonar
Dec 5 at 9:47
2
My taste saysstd::bind
since if forces less disciplined developer to write small functions. Lambda is often overused and grows to ridicules sizes, but still it is easier to use and it is faster.std::bind
creates complex templates which is annoying when analyzing a crash logs.
– Marek R
Dec 5 at 9:51
This does not compile.
– Quentin
Dec 5 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 at 10:08
|
show 4 more comments
up vote
9
down vote
You can use std::bind
std::function<ParentClass *(void)> arr[5] = {
std::bind(&fun1),
std::bind(&fun2),
std::bind(&fun3, false),
std::bind(&fun4),
std::bind(&fun5, 1, 3)
};
now you can do
for(int i=0; i<5; i++)
arr[i]();
You have to make sure every function parameter of all functions are bound.
This also works well with member functions. You just have to bind the object reference (e.g. this
) as first parameter.
1
since C++11 and above there is no point to usebind
since lambda is more handy and faster.
– Marek R
Dec 5 at 9:42
@Marek R - Depending on implementationstd::bind
might just return an lambda because it's return type is unspecified. It's probably just a matter of taste which one you use.
– Detonar
Dec 5 at 9:47
2
My taste saysstd::bind
since if forces less disciplined developer to write small functions. Lambda is often overused and grows to ridicules sizes, but still it is easier to use and it is faster.std::bind
creates complex templates which is annoying when analyzing a crash logs.
– Marek R
Dec 5 at 9:51
This does not compile.
– Quentin
Dec 5 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 at 10:08
|
show 4 more comments
up vote
9
down vote
up vote
9
down vote
You can use std::bind
std::function<ParentClass *(void)> arr[5] = {
std::bind(&fun1),
std::bind(&fun2),
std::bind(&fun3, false),
std::bind(&fun4),
std::bind(&fun5, 1, 3)
};
now you can do
for(int i=0; i<5; i++)
arr[i]();
You have to make sure every function parameter of all functions are bound.
This also works well with member functions. You just have to bind the object reference (e.g. this
) as first parameter.
You can use std::bind
std::function<ParentClass *(void)> arr[5] = {
std::bind(&fun1),
std::bind(&fun2),
std::bind(&fun3, false),
std::bind(&fun4),
std::bind(&fun5, 1, 3)
};
now you can do
for(int i=0; i<5; i++)
arr[i]();
You have to make sure every function parameter of all functions are bound.
This also works well with member functions. You just have to bind the object reference (e.g. this
) as first parameter.
edited Dec 12 at 9:33
answered Dec 5 at 9:27
Detonar
962111
962111
1
since C++11 and above there is no point to usebind
since lambda is more handy and faster.
– Marek R
Dec 5 at 9:42
@Marek R - Depending on implementationstd::bind
might just return an lambda because it's return type is unspecified. It's probably just a matter of taste which one you use.
– Detonar
Dec 5 at 9:47
2
My taste saysstd::bind
since if forces less disciplined developer to write small functions. Lambda is often overused and grows to ridicules sizes, but still it is easier to use and it is faster.std::bind
creates complex templates which is annoying when analyzing a crash logs.
– Marek R
Dec 5 at 9:51
This does not compile.
– Quentin
Dec 5 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 at 10:08
|
show 4 more comments
1
since C++11 and above there is no point to usebind
since lambda is more handy and faster.
– Marek R
Dec 5 at 9:42
@Marek R - Depending on implementationstd::bind
might just return an lambda because it's return type is unspecified. It's probably just a matter of taste which one you use.
– Detonar
Dec 5 at 9:47
2
My taste saysstd::bind
since if forces less disciplined developer to write small functions. Lambda is often overused and grows to ridicules sizes, but still it is easier to use and it is faster.std::bind
creates complex templates which is annoying when analyzing a crash logs.
– Marek R
Dec 5 at 9:51
This does not compile.
– Quentin
Dec 5 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 at 10:08
1
1
since C++11 and above there is no point to use
bind
since lambda is more handy and faster.– Marek R
Dec 5 at 9:42
since C++11 and above there is no point to use
bind
since lambda is more handy and faster.– Marek R
Dec 5 at 9:42
@Marek R - Depending on implementation
std::bind
might just return an lambda because it's return type is unspecified. It's probably just a matter of taste which one you use.– Detonar
Dec 5 at 9:47
@Marek R - Depending on implementation
std::bind
might just return an lambda because it's return type is unspecified. It's probably just a matter of taste which one you use.– Detonar
Dec 5 at 9:47
2
2
My taste says
std::bind
since if forces less disciplined developer to write small functions. Lambda is often overused and grows to ridicules sizes, but still it is easier to use and it is faster. std::bind
creates complex templates which is annoying when analyzing a crash logs.– Marek R
Dec 5 at 9:51
My taste says
std::bind
since if forces less disciplined developer to write small functions. Lambda is often overused and grows to ridicules sizes, but still it is easier to use and it is faster. std::bind
creates complex templates which is annoying when analyzing a crash logs.– Marek R
Dec 5 at 9:51
This does not compile.
– Quentin
Dec 5 at 9:55
This does not compile.
– Quentin
Dec 5 at 9:55
@Quentin - Thanks. Of course you can't have an array of
auto
. I corrected that.– Detonar
Dec 5 at 10:08
@Quentin - Thanks. Of course you can't have an array of
auto
. I corrected that.– Detonar
Dec 5 at 10:08
|
show 4 more comments
up vote
3
down vote
A c++20 solution:
#define RETURNS(...)
noexcept(noexcept(__VA_ARGS__))
-> decltype(__VA_ARGS__)
{ return __VA_ARGS__; }
template<auto f, class R, class...Args>
struct explicit_function_caster {
using Sig=R(Args...);
using pSig=Sig*;
constexpr operator pSig()const {
return (Args...args)->R {
return static_cast<R>(f(std::forward<Args>(args)...));
};
}
};
template<auto f>
struct overload_storer_t {
template<class R, class...Args>
constexpr (*operator R() const)(Args...) const {
return explicit_function_caster<f, R, Args...>{};
}
template<class...Args>
auto operator()(Args&&...args)
RETURNS( f( std::forward<Args>(args)... ) )
};
template<auto f>
overload_storer_t<f> generate_overloads={};
#define OVERLOADS_OF(...)
generate_overloads<
(auto&&...args)
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
>
which is a lot of boilerplate, but gets us:
ParentClass* (*arr[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
void (*arr2[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
basically generate_overloads<x>
takes a constexpr
callable object x
and lets you cast it at compile time to a pointer to a function of any compatible signature and call it with (almost) any signature.
Meanwhile, OVERLOADS_OF
converts a function name into a constexpr
object that does overload resolution on that function name. I use it here because fun3
as a function pointer does not know about its default arguments, but at overload resolution time it does.
In this particular case, it is far easier to just write toy lambdas to do this work; this is just an attempt to automate writing those toy lambdas for arbitrary compatible signatures.
constexpr (*operator R() const)(Args...) const
oh what the hell... Also, isdecltype(args)(args)...
a replacement forstd::forward
or is there additional subtlety?
– Quentin
Dec 5 at 20:56
@Quentin Yes. I don't have the type ofargs
. The cast operator was there because the C++2a compilers didn't likeauto
based partial specialization, so I couldn't easily unpack aSig
: that is a type-deduced conversion operator to function pointer.
– Yakk - Adam Nevraumont
Dec 5 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 at 21:41
1
@Quentin Laugh, I think I converted to a const function pointer in a const method. Accidentally: the fact the function pointer is const is pointless.
– Yakk - Adam Nevraumont
Dec 5 at 22:04
add a comment |
up vote
3
down vote
A c++20 solution:
#define RETURNS(...)
noexcept(noexcept(__VA_ARGS__))
-> decltype(__VA_ARGS__)
{ return __VA_ARGS__; }
template<auto f, class R, class...Args>
struct explicit_function_caster {
using Sig=R(Args...);
using pSig=Sig*;
constexpr operator pSig()const {
return (Args...args)->R {
return static_cast<R>(f(std::forward<Args>(args)...));
};
}
};
template<auto f>
struct overload_storer_t {
template<class R, class...Args>
constexpr (*operator R() const)(Args...) const {
return explicit_function_caster<f, R, Args...>{};
}
template<class...Args>
auto operator()(Args&&...args)
RETURNS( f( std::forward<Args>(args)... ) )
};
template<auto f>
overload_storer_t<f> generate_overloads={};
#define OVERLOADS_OF(...)
generate_overloads<
(auto&&...args)
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
>
which is a lot of boilerplate, but gets us:
ParentClass* (*arr[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
void (*arr2[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
basically generate_overloads<x>
takes a constexpr
callable object x
and lets you cast it at compile time to a pointer to a function of any compatible signature and call it with (almost) any signature.
Meanwhile, OVERLOADS_OF
converts a function name into a constexpr
object that does overload resolution on that function name. I use it here because fun3
as a function pointer does not know about its default arguments, but at overload resolution time it does.
In this particular case, it is far easier to just write toy lambdas to do this work; this is just an attempt to automate writing those toy lambdas for arbitrary compatible signatures.
constexpr (*operator R() const)(Args...) const
oh what the hell... Also, isdecltype(args)(args)...
a replacement forstd::forward
or is there additional subtlety?
– Quentin
Dec 5 at 20:56
@Quentin Yes. I don't have the type ofargs
. The cast operator was there because the C++2a compilers didn't likeauto
based partial specialization, so I couldn't easily unpack aSig
: that is a type-deduced conversion operator to function pointer.
– Yakk - Adam Nevraumont
Dec 5 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 at 21:41
1
@Quentin Laugh, I think I converted to a const function pointer in a const method. Accidentally: the fact the function pointer is const is pointless.
– Yakk - Adam Nevraumont
Dec 5 at 22:04
add a comment |
up vote
3
down vote
up vote
3
down vote
A c++20 solution:
#define RETURNS(...)
noexcept(noexcept(__VA_ARGS__))
-> decltype(__VA_ARGS__)
{ return __VA_ARGS__; }
template<auto f, class R, class...Args>
struct explicit_function_caster {
using Sig=R(Args...);
using pSig=Sig*;
constexpr operator pSig()const {
return (Args...args)->R {
return static_cast<R>(f(std::forward<Args>(args)...));
};
}
};
template<auto f>
struct overload_storer_t {
template<class R, class...Args>
constexpr (*operator R() const)(Args...) const {
return explicit_function_caster<f, R, Args...>{};
}
template<class...Args>
auto operator()(Args&&...args)
RETURNS( f( std::forward<Args>(args)... ) )
};
template<auto f>
overload_storer_t<f> generate_overloads={};
#define OVERLOADS_OF(...)
generate_overloads<
(auto&&...args)
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
>
which is a lot of boilerplate, but gets us:
ParentClass* (*arr[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
void (*arr2[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
basically generate_overloads<x>
takes a constexpr
callable object x
and lets you cast it at compile time to a pointer to a function of any compatible signature and call it with (almost) any signature.
Meanwhile, OVERLOADS_OF
converts a function name into a constexpr
object that does overload resolution on that function name. I use it here because fun3
as a function pointer does not know about its default arguments, but at overload resolution time it does.
In this particular case, it is far easier to just write toy lambdas to do this work; this is just an attempt to automate writing those toy lambdas for arbitrary compatible signatures.
A c++20 solution:
#define RETURNS(...)
noexcept(noexcept(__VA_ARGS__))
-> decltype(__VA_ARGS__)
{ return __VA_ARGS__; }
template<auto f, class R, class...Args>
struct explicit_function_caster {
using Sig=R(Args...);
using pSig=Sig*;
constexpr operator pSig()const {
return (Args...args)->R {
return static_cast<R>(f(std::forward<Args>(args)...));
};
}
};
template<auto f>
struct overload_storer_t {
template<class R, class...Args>
constexpr (*operator R() const)(Args...) const {
return explicit_function_caster<f, R, Args...>{};
}
template<class...Args>
auto operator()(Args&&...args)
RETURNS( f( std::forward<Args>(args)... ) )
};
template<auto f>
overload_storer_t<f> generate_overloads={};
#define OVERLOADS_OF(...)
generate_overloads<
(auto&&...args)
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )
>
which is a lot of boilerplate, but gets us:
ParentClass* (*arr[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
void (*arr2[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
basically generate_overloads<x>
takes a constexpr
callable object x
and lets you cast it at compile time to a pointer to a function of any compatible signature and call it with (almost) any signature.
Meanwhile, OVERLOADS_OF
converts a function name into a constexpr
object that does overload resolution on that function name. I use it here because fun3
as a function pointer does not know about its default arguments, but at overload resolution time it does.
In this particular case, it is far easier to just write toy lambdas to do this work; this is just an attempt to automate writing those toy lambdas for arbitrary compatible signatures.
edited Dec 6 at 14:13
answered Dec 5 at 15:53
Yakk - Adam Nevraumont
181k19188368
181k19188368
constexpr (*operator R() const)(Args...) const
oh what the hell... Also, isdecltype(args)(args)...
a replacement forstd::forward
or is there additional subtlety?
– Quentin
Dec 5 at 20:56
@Quentin Yes. I don't have the type ofargs
. The cast operator was there because the C++2a compilers didn't likeauto
based partial specialization, so I couldn't easily unpack aSig
: that is a type-deduced conversion operator to function pointer.
– Yakk - Adam Nevraumont
Dec 5 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 at 21:41
1
@Quentin Laugh, I think I converted to a const function pointer in a const method. Accidentally: the fact the function pointer is const is pointless.
– Yakk - Adam Nevraumont
Dec 5 at 22:04
add a comment |
constexpr (*operator R() const)(Args...) const
oh what the hell... Also, isdecltype(args)(args)...
a replacement forstd::forward
or is there additional subtlety?
– Quentin
Dec 5 at 20:56
@Quentin Yes. I don't have the type ofargs
. The cast operator was there because the C++2a compilers didn't likeauto
based partial specialization, so I couldn't easily unpack aSig
: that is a type-deduced conversion operator to function pointer.
– Yakk - Adam Nevraumont
Dec 5 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 at 21:41
1
@Quentin Laugh, I think I converted to a const function pointer in a const method. Accidentally: the fact the function pointer is const is pointless.
– Yakk - Adam Nevraumont
Dec 5 at 22:04
constexpr (*operator R() const)(Args...) const
oh what the hell... Also, is decltype(args)(args)...
a replacement for std::forward
or is there additional subtlety?– Quentin
Dec 5 at 20:56
constexpr (*operator R() const)(Args...) const
oh what the hell... Also, is decltype(args)(args)...
a replacement for std::forward
or is there additional subtlety?– Quentin
Dec 5 at 20:56
@Quentin Yes. I don't have the type of
args
. The cast operator was there because the C++2a compilers didn't like auto
based partial specialization, so I couldn't easily unpack a Sig
: that is a type-deduced conversion operator to function pointer.– Yakk - Adam Nevraumont
Dec 5 at 21:06
@Quentin Yes. I don't have the type of
args
. The cast operator was there because the C++2a compilers didn't like auto
based partial specialization, so I couldn't easily unpack a Sig
: that is a type-deduced conversion operator to function pointer.– Yakk - Adam Nevraumont
Dec 5 at 21:06
I can't fathom why there are two
const
s in there though...– Quentin
Dec 5 at 21:41
I can't fathom why there are two
const
s in there though...– Quentin
Dec 5 at 21:41
1
1
@Quentin Laugh, I think I converted to a const function pointer in a const method. Accidentally: the fact the function pointer is const is pointless.
– Yakk - Adam Nevraumont
Dec 5 at 22:04
@Quentin Laugh, I think I converted to a const function pointer in a const method. Accidentally: the fact the function pointer is const is pointless.
– Yakk - Adam Nevraumont
Dec 5 at 22:04
add a comment |
up vote
1
down vote
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function
and lambadas.
Also you should not use C style array, but only std::array
and/or std::vector
.
Also avoid raw pointers, use std::unique_ptr
and std::shared_ptr
.
So simplest and best whay to solve it is:
std::array<std::function<ParentClass*()>,5> arr {
() { return fun1(); },
() { return fun2(); },
() { return fun3(true); },
() { return fun4(); },
() { return fun5(7, 9); }
};
Why not simple array of pointers like in @Quentin answer? He used lambdas, but he can't use lambda which binds anything (if you need to).
2
Downvoted becausestd::function
is a heavyweight facility, and the problem at hand does not require any of the functionality it provides over plain function pointers.
– Quentin
Dec 5 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 at 10:08
add a comment |
up vote
1
down vote
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function
and lambadas.
Also you should not use C style array, but only std::array
and/or std::vector
.
Also avoid raw pointers, use std::unique_ptr
and std::shared_ptr
.
So simplest and best whay to solve it is:
std::array<std::function<ParentClass*()>,5> arr {
() { return fun1(); },
() { return fun2(); },
() { return fun3(true); },
() { return fun4(); },
() { return fun5(7, 9); }
};
Why not simple array of pointers like in @Quentin answer? He used lambdas, but he can't use lambda which binds anything (if you need to).
2
Downvoted becausestd::function
is a heavyweight facility, and the problem at hand does not require any of the functionality it provides over plain function pointers.
– Quentin
Dec 5 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 at 10:08
add a comment |
up vote
1
down vote
up vote
1
down vote
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function
and lambadas.
Also you should not use C style array, but only std::array
and/or std::vector
.
Also avoid raw pointers, use std::unique_ptr
and std::shared_ptr
.
So simplest and best whay to solve it is:
std::array<std::function<ParentClass*()>,5> arr {
() { return fun1(); },
() { return fun2(); },
() { return fun3(true); },
() { return fun4(); },
() { return fun5(7, 9); }
};
Why not simple array of pointers like in @Quentin answer? He used lambdas, but he can't use lambda which binds anything (if you need to).
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function
and lambadas.
Also you should not use C style array, but only std::array
and/or std::vector
.
Also avoid raw pointers, use std::unique_ptr
and std::shared_ptr
.
So simplest and best whay to solve it is:
std::array<std::function<ParentClass*()>,5> arr {
() { return fun1(); },
() { return fun2(); },
() { return fun3(true); },
() { return fun4(); },
() { return fun5(7, 9); }
};
Why not simple array of pointers like in @Quentin answer? He used lambdas, but he can't use lambda which binds anything (if you need to).
edited Dec 6 at 22:34
Remy Lebeau
330k18248438
330k18248438
answered Dec 5 at 9:34
Marek R
12.6k22671
12.6k22671
2
Downvoted becausestd::function
is a heavyweight facility, and the problem at hand does not require any of the functionality it provides over plain function pointers.
– Quentin
Dec 5 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 at 10:08
add a comment |
2
Downvoted becausestd::function
is a heavyweight facility, and the problem at hand does not require any of the functionality it provides over plain function pointers.
– Quentin
Dec 5 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 at 10:08
2
2
Downvoted because
std::function
is a heavyweight facility, and the problem at hand does not require any of the functionality it provides over plain function pointers.– Quentin
Dec 5 at 9:54
Downvoted because
std::function
is a heavyweight facility, and the problem at hand does not require any of the functionality it provides over plain function pointers.– Quentin
Dec 5 at 9:54
7
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 at 10:08
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 at 10:08
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53628791%2fhow-do-i-create-an-array-of-function-pointers-of-different-prototypes%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Why do you want to discard the type from the return? does
ChildClass
not inheritParentClass
?– Caleth
Dec 5 at 9:47
When I use it, I am actually casting it to
ParentClass
. I could make this a ParentClass* instead of void*, but that way I would have to type cast each entry into the array. I instead currently choose to cast it after I retrieve it from the array.– vc669
Dec 5 at 10:00
I miscommunicated through the question that I didn't want to use. I do want to use it. Modified the question accordingly.
– vc669
Dec 5 at 10:32
In your first snippet you have declared
fun4
twice, is that a typo?– Fabio Turati
Dec 5 at 13:48
Yup. Corrected.
– vc669
Dec 5 at 17:16