处理模板中的void类型

Jar*_*edC 11 c++ templates c++11

我有一个模板化的函数,它调用另一个函数并存储它的返回值,然后在返回值之前做一些工作.我想扩展它来处理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);
}
Run Code Online (Sandbox Code Playgroud)

或者可以Foo修改常规版本来处理void类型,在这种情况下基本上什么都不做?我在想,也许我的本地结果可以包含在一个可以处理的类型中void,但也可以将该指派看作是一个交易破坏者.

K-b*_*llo 5

鉴于您的操作不依赖于函数的结果,您可以在没有专业化的情况下执行此操作.返回函数返回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)
    }
};
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样编写你的函数:

template<typename T>
T Foo( T(*Func)() ) 
{
    do_something_helper _dummy_helper; // constructor called here

    return Func();
    // destructor called here
}
Run Code Online (Sandbox Code Playgroud)

对于使用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();
}
Run Code Online (Sandbox Code Playgroud)

使用类型擦除的版本std::function< void() >将更容易编写和使用,但它将是相当低效的.