Trying to take the signatures of two callbacks and generate a callback signature that uses each of their return values.
Given Callbacks A
and B
=> Generate F
Ex 1) A: int(char)
B: double(bool)
=> F: double(int)
Ex 2) A: void(char)
B: void(int)
=> F: void(void)
Ran into a strange compiler error when instantiating a callback with void
as a parameter:
error: invalid parameter type 'void'
template<class Signature>
struct my_func;
template<class Ret, class... Args>
struct my_func<Ret(Args...)>
{};
template<class FuncA, class FuncB>
struct my_fwd;
template<class ORet, class... OArgs,
class Ret, class... Args>
struct my_fwd<
my_func<ORet(OArgs...)>,
my_func<Ret(Args...)>
>
{
my_func< ORet(Ret) > func; // <--- error
};
int main(int, char *[])
{
my_func<void(int)> my3; // (1)
my_func<void(void)> my4; // (2)
my_func<void()> my5; // (3)
my_fwd< decltype(my3), my_func<void(char)> > fwd1; // (4)
my_fwd< decltype(my3), decltype(my4) > fwd2; // (5)
return 0;
}
Though there are no problems with the instantiation of my_func
's with void
(1), (2), (3)
, the my_fwd
's (4) (5)
fail, and I would like to understand why.
I've found a workaround, by specializing my_fwd
for Ret == void
:
// with this specialization i can avoid the error
template<class ORet, class... OArgs,
class... Args>
struct my_fwd<
my_func<ORet(OArgs...)>,
my_func<void(Args...)>
>
{
my_func< ORet() > func;
};
What's the difference between the compiler trying to instantiate inside
my_fwd< my_func<void(int)>, my_func<void(char)> >
:
-> my_func<void(void)> func
and
the manual version in main(): my_func<void(void)> my4
?
Was the void
specialization the correct approach for a fix? Alternatives? I'm obviously not excited about specializations and code duplication.
The difference between instatiating with void
as a template parameter and manually writing void (void)
is that the latter does not produce a function taking a void
parameter. Listing (void)
as a function's parameters is a syntactic construct whose meaning is the same as ()
. It's a legacy from C, where ()
means "parameters are unspecified" and (void)
means "no parameters." C++ removed the unspecified case, and ()
means "no parameters" there.
However, template instantiation happens long after syntactic processing, so actually trying to instantiate a function's parameters (T)
with T = void
results in an error. Just as it would be an error to try to declare a function taking (std::remove_reference<decltype(std::declval<void*>())>::type)
(ie void
actually spelled out as a type).
I am afraid the only way you can solve this is indeed by specialising for void
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.