How do I create an array of function pointers of different prototypes?
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 |
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 '18 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 '18 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 '18 at 10:32
In your first snippet you have declaredfun4
twice, is that a typo?
– Fabio Turati
Dec 5 '18 at 13:48
Yup. Corrected.
– vc669
Dec 5 '18 at 17:16
add a comment |
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 '18 at 17:15
vc669
asked Dec 5 '18 at 9:15
vc669vc669
33128
33128
Why do you want to discard the type from the return? doesChildClass
not inheritParentClass
?
– Caleth
Dec 5 '18 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 '18 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 '18 at 10:32
In your first snippet you have declaredfun4
twice, is that a typo?
– Fabio Turati
Dec 5 '18 at 13:48
Yup. Corrected.
– vc669
Dec 5 '18 at 17:16
add a comment |
Why do you want to discard the type from the return? doesChildClass
not inheritParentClass
?
– Caleth
Dec 5 '18 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 '18 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 '18 at 10:32
In your first snippet you have declaredfun4
twice, is that a typo?
– Fabio Turati
Dec 5 '18 at 13:48
Yup. Corrected.
– vc669
Dec 5 '18 at 17:16
Why do you want to discard the type from the return? does
ChildClass
not inherit ParentClass
?– Caleth
Dec 5 '18 at 9:47
Why do you want to discard the type from the return? does
ChildClass
not inherit ParentClass
?– Caleth
Dec 5 '18 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 '18 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 '18 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 '18 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 '18 at 10:32
In your first snippet you have declared
fun4
twice, is that a typo?– Fabio Turati
Dec 5 '18 at 13:48
In your first snippet you have declared
fun4
twice, is that a typo?– Fabio Turati
Dec 5 '18 at 13:48
Yup. Corrected.
– vc669
Dec 5 '18 at 17:16
Yup. Corrected.
– vc669
Dec 5 '18 at 17:16
add a comment |
5 Answers
5
active
oldest
votes
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 '18 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 '18 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 '18 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 '18 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 '18 at 12:33
|
show 2 more comments
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 '18 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 '18 at 12:55
add a comment |
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 '18 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 '18 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 '18 at 9:51
This does not compile.
– Quentin
Dec 5 '18 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 '18 at 10:08
|
show 4 more comments
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 '18 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 '18 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 '18 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 '18 at 22:04
add a comment |
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function
and lambdas.
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 way 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 '18 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 '18 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',
autoActivateHeartbeat: false,
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
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 '18 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 '18 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 '18 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 '18 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 '18 at 12:33
|
show 2 more comments
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 '18 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 '18 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 '18 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 '18 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 '18 at 12:33
|
show 2 more comments
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 '18 at 10:34
answered Dec 5 '18 at 9:18
QuentinQuentin
45.9k589142
45.9k589142
Does this make the return type of the functionsvoid
?
– vc669
Dec 5 '18 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 '18 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 '18 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 '18 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 '18 at 12:33
|
show 2 more comments
Does this make the return type of the functionsvoid
?
– vc669
Dec 5 '18 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 '18 at 10:18
1
Actually, one would only need lambdas forfun3
andfun5
...
– Aconcagua
Dec 5 '18 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 '18 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 '18 at 12:33
Does this make the return type of the functions
void
?– vc669
Dec 5 '18 at 10:14
Does this make the return type of the functions
void
?– vc669
Dec 5 '18 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 '18 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 '18 at 10:18
1
1
Actually, one would only need lambdas for
fun3
and fun5
...– Aconcagua
Dec 5 '18 at 12:08
Actually, one would only need lambdas for
fun3
and fun5
...– Aconcagua
Dec 5 '18 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 '18 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 '18 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 '18 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 '18 at 12:33
|
show 2 more comments
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 '18 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 '18 at 12:55
add a comment |
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 '18 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 '18 at 12:55
add a comment |
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 '18 at 12:58
answered Dec 5 '18 at 9:28
datenwolfdatenwolf
132k10132236
132k10132236
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 '18 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 '18 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 '18 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 '18 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 '18 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 '18 at 12:13
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 '18 at 12:55
@Aconcagua: That's a very good point!
– datenwolf
Dec 5 '18 at 12:55
add a comment |
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 '18 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 '18 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 '18 at 9:51
This does not compile.
– Quentin
Dec 5 '18 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 '18 at 10:08
|
show 4 more comments
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 '18 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 '18 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 '18 at 9:51
This does not compile.
– Quentin
Dec 5 '18 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 '18 at 10:08
|
show 4 more comments
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 '18 at 9:33
answered Dec 5 '18 at 9:27
DetonarDetonar
988111
988111
1
since C++11 and above there is no point to usebind
since lambda is more handy and faster.
– Marek R
Dec 5 '18 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 '18 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 '18 at 9:51
This does not compile.
– Quentin
Dec 5 '18 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 '18 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 '18 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 '18 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 '18 at 9:51
This does not compile.
– Quentin
Dec 5 '18 at 9:55
@Quentin - Thanks. Of course you can't have an array ofauto
. I corrected that.
– Detonar
Dec 5 '18 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 '18 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 '18 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 '18 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 '18 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 '18 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 '18 at 9:51
This does not compile.
– Quentin
Dec 5 '18 at 9:55
This does not compile.
– Quentin
Dec 5 '18 at 9:55
@Quentin - Thanks. Of course you can't have an array of
auto
. I corrected that.– Detonar
Dec 5 '18 at 10:08
@Quentin - Thanks. Of course you can't have an array of
auto
. I corrected that.– Detonar
Dec 5 '18 at 10:08
|
show 4 more comments
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 '18 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 '18 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 '18 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 '18 at 22:04
add a comment |
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 '18 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 '18 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 '18 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 '18 at 22:04
add a comment |
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 '18 at 14:13
answered Dec 5 '18 at 15:53
Yakk - Adam NevraumontYakk - Adam Nevraumont
184k19191376
184k19191376
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 '18 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 '18 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 '18 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 '18 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 '18 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 '18 at 21:06
I can't fathom why there are twoconst
s in there though...
– Quentin
Dec 5 '18 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 '18 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 '18 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 '18 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 '18 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 '18 at 21:06
I can't fathom why there are two
const
s in there though...– Quentin
Dec 5 '18 at 21:41
I can't fathom why there are two
const
s in there though...– Quentin
Dec 5 '18 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 '18 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 '18 at 22:04
add a comment |
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function
and lambdas.
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 way 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 '18 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 '18 at 10:08
add a comment |
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function
and lambdas.
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 way 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 '18 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 '18 at 10:08
add a comment |
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function
and lambdas.
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 way 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 lambdas.
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 way 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 12 hours ago
marc_s
575k12811101257
575k12811101257
answered Dec 5 '18 at 9:34
Marek RMarek R
12.8k22674
12.8k22674
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 '18 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 '18 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 '18 at 9:54
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 '18 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 '18 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 '18 at 9:54
7
7
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 '18 at 10:08
I'm tempted to give an upvote for "Lambadas" :)
– Willem van Rumpt
Dec 5 '18 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.
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 '18 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 '18 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 '18 at 10:32
In your first snippet you have declared
fun4
twice, is that a typo?– Fabio Turati
Dec 5 '18 at 13:48
Yup. Corrected.
– vc669
Dec 5 '18 at 17:16