Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在模板中处理void类型_C++_Templates_C++11 - Fatal编程技术网

C++ 在模板中处理void类型

C++ 在模板中处理void类型,c++,templates,c++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 re

我有一个模板函数,它调用另一个函数并存储其返回值,然后在返回值之前做一些工作。我想扩展它来处理
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);
}
模板
T Foo(T(*Func)()
{
//先做一些事情(例如一些设置)
T结果=Func();
//之后做某事(例如,拆下一些东西)
返回结果;
}
//这是唯一的选择吗?
模板
无效Foo(无效(*Func)()
{
//先做一些事情(例如一些设置)
Func();
//之后做某事(例如,拆下一些东西)
返回;
}
无效条(){}
int BarInt(){return 1;}
int main()
{
富(及霸菱),;
Foo&Bar;
}

或者可以修改
Foo
的常规版本来处理
void
类型,并且在这种情况下基本上什么都不做?我在想,也许我的本地结果可以包装成一个类型,可以处理
void
maybe,但也可以将分配视为交易破坏者。

不,你需要专门化,因为你不能存储void(如
T result=Func();

如果您永远不会使用该值,并且您可以将调用Func作为最后一件事,那么您实际上可以:

return Func( );
如果func返回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( ) { }
};
模板
类调用包装器{
公众:
调用包装器(std::functionf)
:temp(std::move(f()))
{ }
返回和销毁(&&U){
返回标准::移动(温度);
}
私人:
R温度;
};
模板<>
类调用\u包装{
公众:
调用包装器(std::functionf{f();}
无效返回和销毁(){}
};
然后,您可以在您将要编写的所有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( );
}
模板
T Foo(T(*Func)()
{
//先做一些事情(例如一些设置)
调用_wrappercw(Func);
//之后做某事(例如,拆下一些东西)
返回cw.return_和_destroy();
}

如果您所做的只是获取和释放锁,那么您应该使用RAII,而不是调用锁定/解锁功能。如果
Func
可以抛出,就好像它在不调用它之后执行代码一样,这一点尤其正确

一旦你有了一个RAII锁(或者如果你需要的不仅仅是锁的话,还有一段时间的RAII对象),你可以简单地完成这项工作,这项工作适用于
void

template<typename T>
T Foo( T(*Func)() ) 
{
    lock my_lock;
    return Func();
}
模板
T Foo(T(*Func)()
{
锁上我的锁;
返回Func();
}

模板
T Foo(T(*Func)()
{
结构rai_包装器{
rai_包装(T(*Func)():Func(Func){
//预效应
}
~raii_wrapper(){
//后效
}
T(*Func)();
}行动(Func);
返回函数;
}

如果您的操作不依赖于函数的结果,则无需专门化即可完成。返回
void
的函数可以返回类型为
void
的表达式。因此
返回
部分并不麻烦,但是您需要找到一种方法来执行前后操作。构造函数和析构函数将帮助您:

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
}
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();
}
模板
T Foo(T(*Func)()
{
do\u something\u helper\u dummy\u helper;//这里调用了构造函数
返回Func();
//这里调用了析构函数
}
如您所述,对于使用lambdas的更通用的解决方案,它可能如下所示:

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

    return Func();
    // destructor called here
}
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();
}
template
结构范围保护
{
范围保护(前置和前置、后置和后置)
:_post(std::forward(post))
{
pre();
}
~scope_guard()
{
_post();
}
邮政(邮政);;
};
模板
范围保护制作范围保护(Pre&Pre,Post&Post)
{
返回范围_guard(std::forward
(Pre),std::forward(Post));
}
模板
T Foo(T(*Func)()
{
自动做某事\u助手=
制造防护罩(
[](){/*先做点什么(例如拿把锁)*/},
[](){/*在之后做某事(例如释放锁)*/}
);
返回Func();
}

使用
std::function
的类型擦除版本更易于编写和使用,但效率较低。

不确定这是否有效,但:

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;
}
模板
无效Foo(T(*Func)()
{
//先做一些事情(例如一些设置)
返回拆卸(Func());
}
模板
T拆卸(T结果)
{
//事后做某事
返回结果;
}

是否要执行与刚刚得到的
结果相关的操作?
否。实际上,Func()的前置和后置代码非常重要。我要补充一点。请发布您对
结果所做的操作。我没有对
结果做任何操作,它只是
Func()
返回的内容,我很乐意返回。这个函数的关键是,在其他操作的中间调用<代码>函数()/代码>。除了抓取锁之外,还有其他的前、后代码,但RAII建议的值是1。我必须考虑这是否可行。@JaredC更新了一个不同的示例。使用lambdas和一些在销毁时调用lamdas的现有代码,这可以很好地工作。我可以处理这个问题,但是这会有一个更好的答案:-)@JaredC:注意,
operator->
重载的奇怪要求对于cod之前/之后是一个很好的方法