Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.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++ 将不可复制的闭包对象传递给std::function参数_C++_Lambda_Move Semantics_C++14 - Fatal编程技术网

C++ 将不可复制的闭包对象传递给std::function参数

C++ 将不可复制的闭包对象传递给std::function参数,c++,lambda,move-semantics,c++14,C++,Lambda,Move Semantics,C++14,在C++14中,lambda表达式可以通过使用捕获初始值设定项从变量中移动来捕获变量。但是,这使得生成的闭包对象不可复制。如果我有一个接受std::function参数(我不能更改)的现有函数,我就不能传递闭包对象,因为std::function的构造函数要求给定的functor是CopyConstructible #include <iostream> #include <memory> void doit(std::function<void()> f)

在C++14中,lambda表达式可以通过使用捕获初始值设定项从变量中移动来捕获变量。但是,这使得生成的闭包对象不可复制。如果我有一个接受
std::function
参数(我不能更改)的现有函数,我就不能传递闭包对象,因为
std::function
的构造函数要求给定的functor是
CopyConstructible

#include <iostream>
#include <memory>

void doit(std::function<void()> f) {
    f();
}

int main()
{
    std::unique_ptr<int> p(new int(5));
    doit([p = std::move(p)] () { std::cout << *p << std::endl; });
}
#包括
#包括
void doit(std::函数f){
f();
}
int main()
{
std::unique_ptr p(新int(5));

doit([p=std::move(p)](){std::cout如果闭包对象的生存期不是问题,则可以在引用包装器中传递它:

int main()
{
    std::unique_ptr<int> p(new int(5));
    auto f = [p = std::move(p)]{
        std::cout << *p << std::endl;
    };
    doit(std::cref(f));
}
intmain()
{
std::unique_ptr p(新int(5));
自动f=[p=std::move(p)]{

std::cout有这种方法:

template< typename signature >
struct make_copyable_function_helper;
template< typename R, typename... Args >
struct make_copyable_function_helper<R(Args...)> {
  template<typename input>
  std::function<R(Args...)> operator()( input&& i ) const {
    auto ptr = std::make_shared< typename std::decay<input>::type >( std::forward<input>(i) );
    return [ptr]( Args... args )->R {
      return (*ptr)(std::forward<Args>(args)...);
    };
  }
};

template< typename signature, typename input >
std::function<signature> make_copyable_function( input && i ) {
  return make_copyable_function_helper<signature>()( std::forward<input>(i) );
}
更高级的版本推迟了类型擦除,并添加了一层完美的转发以减少开销:

template<typename input>
struct copyable_function {
  typedef typename std::decay<input>::type stored_input;
  template<typename... Args>
  auto operator()( Args&&... args )->
    decltype( std::declval<input&>()(std::forward<Args>(args)...) )
  {
    return (*ptr)(std::forward<Args>(args));
  }
  copyable_function( input&& i ):ptr( std::make_shared<stored_input>( std::forward<input>(i) ) ) {}
  copyable_function( copyable_function const& ) = default;
private:
  std::shared_ptr<stored_input> ptr;
};
template<typename input>
copyable_function<input> make_copyable_function( input&& i ) {
  return {std::forward<input>(i)}; 
}
模板
结构可复制函数{
typedef typename std::decage::type存储的\u输入;
模板
自动运算符()(Args&&…Args)->
decltype(std::declval()(std::forward(args)…)
{
返回(*ptr)(标准::转发(args));
}
可复制_函数(输入和&i):ptr(std::make_共享(std::forward(i)){
可复制函数(可复制函数常量&)=默认值;
私人:
std::共享的ptr;
};
模板
可复制功能使可复制功能(输入和输入){
返回{std::forward(i)};
}
它不需要您传入签名,在某些情况下可能会稍微更有效,但使用了更模糊的技术

在C++14中,这可以变得更加简短:

template< class F >
auto make_copyable_function( F&& f ) {
  using dF=std::decay_t<F>;
  auto spf = std::make_shared<dF>( std::forward<F>(f) );
  return [spf](auto&&... args)->decltype(auto) {
    return (*spf)( decltype(args)(args)... );
  };
}
模板
自动生成可复制功能(F&&F){
使用dF=std::decation\u t;
自动spf=std::使_共享(std::转发(f));
返回[spf](自动&&…参数)->decltype(自动){
返回(*spf)(decltype(args)(args)…);
};
}

完全不需要helper类型。

如果你知道你实际上不打算复制你的函数对象,那么你可以把它包装成一个类型,让编译器认为它是可复制的:

struct ThrowOnCopy {
  ThrowOnCopy() = default;
  ThrowOnCopy(const ThrowOnCopy&) { throw std::logic_error("Oops!"); }
  ThrowOnCopy(ThrowOnCopy&&) = default;
  ThrowOnCopy& operator=(ThrowOnCopy&&) = default;
};

template<typename T>
  struct FakeCopyable : ThrowOnCopy
  {
    FakeCopyable(T&& t) : target(std::forward<T>(t)) { }

    FakeCopyable(FakeCopyable&&) = default;

    FakeCopyable(const FakeCopyable& other)
    : ThrowOnCopy(other),                             // this will throw
      target(std::move(const_cast<T&>(other.target))) // never reached
    { }

    template<typename... Args>
      auto operator()(Args&&... a)
      { return target(std::forward<Args>(a)...); }

    T target;
  };


template<typename T>
  FakeCopyable<T>
  fake_copyable(T&& t)
  { return { std::forward<T>(t) }; }


// ...

doit( fake_copyable([p = std::move(p)] () { std::cout << *p << std::endl; }) );
struct ThrowOnCopy{
ThrowOnCopy()=默认值;
ThrowOnCopy(const ThrowOnCopy&){throw std::logic_error(“Oops!”);}
ThrowOnCopy(ThrowOnCopy&&)=默认值;
ThrowOnCopy&运算符=(ThrowOnCopy&&)=默认值;
};
模板
结构伪造可复制:ThrowOnCopy
{
FakeCopyable(T&&T):目标(std::forward(T)){
FakeCopyable(FakeCopyable&&)=默认值;
伪造复制品(常量伪造复制品和其他)
:ThrowOnCopy(其他),//这将抛出
目标(std::move(const_cast(other.target))//从未到达
{ }
模板
自动运算符()(Args&&…a)
{返回目标(std::forward(a)…);}
T靶;
};
模板
伪造的
假冒可复制(T&T)
{return{std::forward(t)};}
// ...

doit(fake_copyable([p=std::move(p)]({std::cout)如果对象的闭包不是问题,您能不能让doit接受一个const函数&?@MadScienceDreams它可以与一个特定的实现一起工作,将函数对象构造为
std::function bar{std::move(f)};
如果该实现避免实例化
std::function
的复制构造函数,那么它将不是可移植的行为,因为
std::function
明确要求functor在[func.wrap.func.con]中可复制构造/7.事实上,.@MadScienceDreams我假设
std::function
的实现通过使用包含“虚拟副本构造函数”的抽象接口包装传递的函子来实现类型擦除我熟悉的C++的每一个实现都实例化了一个声明虚填充VTABLE的模板的所有成员,尽管该标准表示未使用的虚拟成员的实例化是特定于实现的。显然,虚拟复制构造函数是函数“代码>可复制的< /代码>要求的源代码。rs传递给
std::function
。C++0x草稿并不总是有
CopyConstructible
要求,它是由添加的。实现不必使用任何虚拟函数(GCC的实现也不需要)但类型擦除仍然意味着,如果目标可能不可复制,则无法提供可复制的包装。这是我在代理方面遇到的一个问题越来越多(上次出现时,它是以通用方式实现PIMPL的)。问题是对象的能力由其类型决定(此处
std::function
)因此,如果您想要的对象只有在传递的对象可复制时才可复制,如果传递的对象可移动时才可移动,等等……不幸的是,使用相同的类型=>是不可能的,我猜位掩码作为另一个模板参数(
std::function
)可以,但可能会很闷:/I我有自己的类型擦除支架用于此目的。据我所知,没有任何建议来改善这种情况,尽管我被告知有国家机构对该主题的评论。可能
std::function\u ref
将能够处理此问题。否则,像这样使用
std::cref
下面的答案之一。此解决方案要求
T
是默认可构造的。@Sogartar很好,谢谢。我已经修复了代码,现在就可以工作了。
template< class F >
auto make_copyable_function( F&& f ) {
  using dF=std::decay_t<F>;
  auto spf = std::make_shared<dF>( std::forward<F>(f) );
  return [spf](auto&&... args)->decltype(auto) {
    return (*spf)( decltype(args)(args)... );
  };
}
struct ThrowOnCopy {
  ThrowOnCopy() = default;
  ThrowOnCopy(const ThrowOnCopy&) { throw std::logic_error("Oops!"); }
  ThrowOnCopy(ThrowOnCopy&&) = default;
  ThrowOnCopy& operator=(ThrowOnCopy&&) = default;
};

template<typename T>
  struct FakeCopyable : ThrowOnCopy
  {
    FakeCopyable(T&& t) : target(std::forward<T>(t)) { }

    FakeCopyable(FakeCopyable&&) = default;

    FakeCopyable(const FakeCopyable& other)
    : ThrowOnCopy(other),                             // this will throw
      target(std::move(const_cast<T&>(other.target))) // never reached
    { }

    template<typename... Args>
      auto operator()(Args&&... a)
      { return target(std::forward<Args>(a)...); }

    T target;
  };


template<typename T>
  FakeCopyable<T>
  fake_copyable(T&& t)
  { return { std::forward<T>(t) }; }


// ...

doit( fake_copyable([p = std::move(p)] () { std::cout << *p << std::endl; }) );