[英]Type specialization at compile-time
我正在编写一个与std::function
共享几个不同特性的类(或者至少类在很多方面类似)。 正如大家都知道std::function
是通过指定模板参数实例化(即std::function<void (std::string&)>
),它是我的课一样。 我有一个例外,不过,我想在我的课,专门的单一功能,如果返回值是无效的( 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:在'Ret Test :: operator()(Args ...)的实例化中[含Ret = void; Args = {char}]':。/ test.cpp:27:10:从这里需要./test.cpp:18:8:错误:变量或字段'returnVal'声明为void ./test.cpp:19:11 :error:带有值的return语句,在函数返回'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
如果这是模板中唯一的功能,那么部分特化是一个更简单的解决方案,不需要滥用继承。
一种解决方案是部分专门化您的类模板。
#include <iostream>
#include <type_traits>
template <typename T> class Test { };
template <typename Ret, typename... Args>
class Test<Ret (Args...)>
{
public:
Ret operator()(Args...)
{
std::cout<<"non-void function"<<std::endl;
Ret returnVal;
return returnVal;
}
};
template <typename... Args>
class Test<void (Args...)>
{
public:
void operator()(Args...)
{
std::cout<<"void function"<<std::endl;
}
};
int main(int argc, char * argv[])
{
Test<void (char)> test;
test('k');
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.