我正在编写一个与std :: function共享几个不同特性的类(或者至少类在很多方面类似).众所周知,通过指定模板参数(即std :: function< void(std :: string&)>)来实例化std :: function,对我的类来说是一样的.我有一个例外,我想在我的类中专门化一个函数,如果返回值为void(std :: function<“return value”(“parameters”>).我需要在编译时完成此操作,我只是不能使它工作.这是一些测试代码的解释:
#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'); }
正如您可以清楚地看到的,如果编译器在上述测试中没有删除’else’分支,我的代码将尝试创建一个void值(即void returnVal;).问题是编译器没有删除分支,所以我最终得到一个编译器错误:
./test.cpp: In instantiation of ‘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 a value,in function returning ‘void’
[-fpermissive]
通常会将std :: enable_if与std :: is_void结合使用,问题在于我不想专注于函数模板,而是在类模板上.
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...) { // It's a void function // ... } };
./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]
如果我只是愚蠢的话,我很抱歉,答案很明显.我对模板很新,我在其他任何线程/问题中找不到合适的答案.
解决方法
从您的描述中有一些不完全清楚的事情,所以我将从最常见的答案开始.
假设模板具有必须保持相同行为的其他函数,并且您只想重新定义该特定函数的行为,最简单的答案是将模板拆分为两个,并使用继承来合并它们.此时,您可以在基本模板上使用部分模板特化:
template <typename T,typename... Args> struct tmpl_base { T operator()( Args... args ) { //generic } }; template <typename... Args> struct tmpl_base<void,Args...> { void operator()( Args... args ) { } }; template <typename Ret,typename... Args> class Test<Ret (Args...)> : tmp_base<Ret,Args...> { // do not declare/define operator(),maybe bring the definition into scope: using tmp_base<Ret,Args...>::operator(); // Rest of the class