Reputation: 1763
I have a template function template<class T> T exc(T())
where T can sometime be void.
This function is used to execute a function and return the value (if it's not void).
This is the simplified content of exc
(of course I have other content =p)
template<class T> T exc(T (*func)()){
if(strcmp(typeid(T).name(), "void")){
T obj = (*func)();
// there are something to do with obj
return obj;
} else{
(*func)();
}
}
// in main:
exc<void>([]() -> void{std::cout << "I'm too lazy to type another function"
<< " so I use lambda" << std::endl;});
As you may know, strcmp
return 0
when typeid(T).name()
equals to "void"
.
That is, there are no problem with runtime theoretically. However, this is the error
error C2182 : illegal use of type 'void'
I use MSVC cl command line compiler, and I think the problem may be caused by the compiler which substitute each template type from where function is invoked for T, so at T obj
, the error occur.
I want to ask that is there any alternate solution for this? Is there any other way to declare obj so that the compiler treat it as 'correct'? Or should I override exc with void exc(void (*func)())
?
Upvotes: 2
Views: 72
Reputation: 43662
Overloading is the answer if your "actual code" does something more involved with the templated type
template<class T> T exc(T (*func)()){
T obj = (*func)();
// there's something to do with obj
return obj;
}
void exc(void (*func)()){
// something to do with void?
(*func)();
}
(anyway you will not be able to explicitly state the template parameter in the void
case, a specialization could do it but pay attention to some overloading vs specialization resolutions).
Finally you could as well return a void
call
void fun() {}
template <class T>
T exc(T (*func)()) {
return func();
}
exc<void>(fun);
One thing to keep in mind is that when compiling templated code, all the in-scope branches should be valid at any time. An if branch is NOT going to be "dead-code eliminated" magically if the templated type doesn't match - it will yield an error.
Upvotes: 2
Reputation: 217293
You have error because the two branches has to be valid and
if(strcmp(typeid(T).name(), "void")){
T obj = (*func)();
// there are something to do with obj
return obj;
}
is not valid for T == void
(even if the branch would not be taken)
You may use overload to solve your problem:
template<class T> T exc(T (*func)()){
T obj = (*func)();
// there are something to do with obj
return obj;
}
void exc(void (*func)()){
(*func)();
}
Upvotes: 1
Reputation: 63124
Just do :
template <class T>
T exc(T (*func)()) {
return func();
}
You can return
an expression of void
type from a void function.
Edit: if you need to apply a special treatment to obj
, don't specialize your function template. Overload it :
void exc(void (*func)()) {
func();
}
Upvotes: 2