I am writing a class that has several different functions with std::function
(or at least the classes are much alike). As you know, std::function
is created by specifying template parameters (for example, std::function<void (std::string&)>
), for my class it is the same. I have an exception, although I want to specialize a single function in my class if the return value is invalid ( std::function<"return value" ("parameters">
). I need this to be done at compile time, and I just can't make it work properly. Here is a sample code to explain:
#include <iostream> #include <type_traits> template <typename T> class Test { }; template <typename Ret, typename... Args> class Test<Ret (Args...)> { public: Ret operator()(Args...) { if(std::is_void<Ret>::value) { // Do something... } else /* Not a void function */ { Ret returnVal; return returnVal; } } }; int main(int argc, char * argv[]) { Test<void (char)> test; test('k'); }
As you can clearly see, if the compiler does not remove the else branch in the above test, my code will try to create a void value (ie void returnVal;
). The problem is that the compiler does not delete the branch, so I end up with a compiler error:
./test.cpp: when creating "Ret Test :: operator () (Args ...) [with Ret = void; Args = {char}] :. /test.cpp:27:10: required from here. / test .cpp: 18: 8: error: variable or field "returnVal declared void./test.cpp:19:11: error: return-statement with value, in function returning 'void' [-fpermissive]
You can usually use std::enable_if
in combination with std::is_void
, the problem is that I do not want to specialize in the function template, but in the class template.
template <typename Ret, typename... Args> class Test<Ret (Args...)> { public: typename std::enable_if<!std::is_void<Ret>::value, Ret>::type Ret operator()(Args...) { Ret returnVal; return returnVal; } typename std::enable_if<std::is_void<Ret>::value, Ret>::type Ret operator()(Args...) {
If I use the above code, instead I get even more errors and without a solution
./test.cpp:11:2: error: expected ';' at end of member declaration ./test.cpp:11:2: error: declaration of 'typename std::enable_if<(! std::is_void<_Tp>::value), Ret>::type Test<Ret(Args ...)>::Ret' ./test.cpp:6:11: error: shadows template parm 'class Ret' ./test.cpp:11:24: error: ISO C++ forbids declaration of 'operator()' with no type [-fpermissive] ./test.cpp:18:2: error: expected ';' at end of member declaration ./test.cpp:18:2: error: declaration of 'typename std::enable_if<std::is_void<_Tp>::value, Ret>::type Test<Ret(Args ...)>::Ret' ./test.cpp:6:11: error: shadows template parm 'class Ret' ./test.cpp:18:24: error: ISO C++ forbids declaration of 'operator()' with no type [-fpermissive] ./test.cpp:18:6: error: 'int Test<Ret(Args ...)>::operator()(Args ...)' cannot be overloaded ./test.cpp:11:6: error: with 'int Test<Ret(Args ...)>::operator()(Args ...)' ./test.cpp: In member function 'int Test<Ret(Args ...)>::operator()(Args ...)': ./test.cpp:22:2: warning: no return statement in function returning non-void [-Wreturn-type] ./test.cpp: In instantiation of 'int Test<Ret(Args ...)>::operator()(Args ...) [with Ret = void; Args = {char}]': ./test.cpp:28:10: required from here ./test.cpp:13:7: error: variable or field 'returnVal' declared void ./test.cpp: In member function 'int Test<Ret(Args ...)>::operator()(Args ...) [with Ret = void; Args = {char}]': ./test.cpp:15:2: warning: control reaches end of non-void function [-Wreturn-type]
Sorry if I'm just dumb and the answer is obvious. I am new to templates and I could not find a suitable answer in any of the other questions / questions.