处理模板中的void类型
handling void type in template
我有一个模板化的函数,它调用另一个函数并存储其返回值,然后在返回值之前做一些工作。我想扩展它来处理T = void
,并且想知道专业化是否是我唯一的选择。
template<typename T>
T Foo( T(*Func)() )
{
// do something first (e.g. some setup)
T result = Func();
// do something after (e.g. some tear down)
return result;
}
// Is this specialization the only option?
template<>
void Foo<void>( void(*Func)() )
{
// do something first (e.g. some setup)
Func();
// do something after (e.g. some tear down)
return;
}
void Bar() {}
int BarInt() { return 1; }
int main()
{
Foo<int>(&BarInt);
Foo<void>(&Bar);
}
或者可以修改Foo
的常规版本来处理void
类型,在这种情况下基本上什么都不做?我在想,也许我的本地结果可以包装在一个类型,可以处理void
也许,但也可以看到分配是一个交易破坏者。
如果您的操作不依赖于函数的结果,则无需专门化即可完成该操作。返回void
的函数返回void
类型的表达式是可以的。所以return
部分不是麻烦的一个,但你需要找出一种方法来做前和后操作。构造函数和析构函数将在这方面提供帮助:
struct do_something_helper
{
do_something_helper()
{
// do something first (e.g. take a lock)
}
~do_something_helper()
{
// do something after (e.g. release a lock)
}
};
然后你可以这样写你的函数:
template<typename T>
T Foo( T(*Func)() )
{
do_something_helper _dummy_helper; // constructor called here
return Func();
// destructor called here
}
对于使用lambdas的更通用的解决方案,如您所评论的,它可能看起来像这样:
template< typename Pre, typename Post >
struct scope_guard
{
scope_guard( Pre&& pre, Post&& post )
: _post( std::forward< Post >( post ) )
{
pre();
}
~scope_guard()
{
_post();
}
Post _post;
};
template< typename Pre, typename Post >
scope_guard< Pre, Post > make_scope_guard( Pre&& pre, Post&& post )
{
return scope_guard< Pre, Post >( std::forward< Pre >( pre ), std::forward< Post >( post ) );
}
template<typename T>
T Foo( T(*Func)() )
{
auto do_something_helper =
make_scope_guard(
[](){ /* do something first (e.g. take a lock) */ },
[](){ /* do something after (e.g. release a lock) */ }
);
return Func();
}
使用std::function< void() >
的类型擦除的版本更容易编写和使用,但效率相当低。
如果你所做的只是获取和释放一个锁,那么你应该使用RAII而不是调用lock/unlock函数。如果Func
可以抛出,这尤其正确,就好像它做了之后的代码将不会被调用。
一旦你有了一个RAII锁(或者如果你需要更多的RAII对象),你可以简单地执行void
:
template<typename T>
T Foo( T(*Func)() )
{
lock my_lock;
return Func();
}
template<typename T>
T Foo( T(*Func)() )
{
struct raii_wrapper {
raii_wrapper(T(*Func)()) : Func(Func) {
// pre effects
}
~raii_wrapper() {
// post effects
}
T(*Func)();
} actions(Func);
return Func;
}
不,您需要专门化,因为您不能存储void(如T result = Func();
)。
如果你永远不会使用这个值,并且你可以在最后调用Func,那么你实际上可以:
return Func( );
if函数返回void或一个类型,因为以下是合法的:
void f();
void g() {
return f();
}
但是如果需要临时存储返回值,则需要专门化。
然而,如果你要创建很多这样的辅助函数(Foo),并且你不想每次都为void专门指定特定的Foo,你可以创建一个包装调用者,它将执行调用,并在你需要的时候返回值,可以是void或其他实际类型:
template< typename R >
class call_wrapper {
public:
call_wrapper( std::function< R( void ) > f )
: temp( std::move( f( ) ) )
{ }
R&& return_and_destroy( ) {
return std::move( temp );
}
private:
R temp;
};
template< >
class call_wrapper< void > {
public:
call_wrapper( std::function< void(void) > f ) { f( ); }
void return_and_destroy( ) { }
};
然后你可以在你要写的所有Foo中执行以下操作,不需要专门化,因为它在上面的包装器中已经被一次性处理过了:
template<typename T>
T Foo( T(*Func)() )
{
// do something first (e.g. some setup)
call_wrapper< T > cw( Func );
// do something after (e.g. some tear down)
return cw.return_and_destroy( );
}
不确定这是否有效,但是:
template<>
void Foo<T>( T(*Func)() )
{
// do something first (e.g. some setup)
return tearDown(Func());
}
template<>
T tearDown<T>( T result)
{
// do something after
return result;
}
- 不能将 "void *" 类型的值分配给类型 "TCHAR" 的实体
- 不能将 "void *" 类型的值分配给类型 "RANDOMSTRUCT *" 的实体
- 在C++中将uint64_t转换为void类型的目的是什么
- 带有void类型和参数的C++11模板专用化
- 编写完整专业化以识别void类型的问题
- 非类型模板参数可以是 "void*" 类型吗?
- 如何将“void *”类型更改为“字符串”类型
- 智能感知:不能将 "void" 类型的值分配给类型 "double" 的实体
- 传递对指向 void 类型的指针的指针的引用
- 无法从 void* 类型转换(类名::)() 以键入 void*(*)(void*)
- 如何使用void类型处理递归回溯返回
- 异步返回 void 类型的未来,而不是预期类型
- std::is_same 表示 void 函数 (..) 和 void 类型
- void * 类型的参数与类型的参数不兼容
- C++:无法使用 'void' 类型的右值初始化 'void (*)()' 类型的参数
- void类型的OpenGL C++参数与void(*)()类型的参数不兼容
- 为什么我们不能声明一个 void 类型的变量?
- 如果void类型函数什么都不返回会发生什么
- 在声明后将int类型强制转换为void类型
- C++ 动态数组:不能使用 "void" 类型的值来初始化 "int" 类型的实体