Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/327.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++ 如何通过未指定的调用包装器绑定成员函数模板_C++_C++11_Stdbind - Fatal编程技术网

C++ 如何通过未指定的调用包装器绑定成员函数模板

C++ 如何通过未指定的调用包装器绑定成员函数模板,c++,c++11,stdbind,C++,C++11,Stdbind,我尝试使用VC11和g++4.7.2编译以下示例: #include <functional> class X { public: template <typename T> explicit X(T t) { std::bind(&X::invoke<T>, this, t)(); } private: template <typename T> void invoke(T t) { t();

我尝试使用VC11和g++4.7.2编译以下示例:

#include <functional>

class X {
public:
  template <typename T>
  explicit X(T t)
  {
    std::bind(&X::invoke<T>, this, t)();
  }
private:
  template <typename T>
  void invoke(T t)
  {
    t();
  }
};

class Y {
  public:
    void foo() {
      //...
    }
};


int main() {
  Y y;
  X x(std::bind(&Y::foo, &y));
  return 0;
}
#包括
X类{
公众:
模板
显式X(T)
{
std::bind(&X::invoke,this,t)();
}
私人:
模板
无效调用(T)
{
t();
}
};
Y类{
公众:
void foo(){
//...
}
};
int main(){
Y;
X(std::bind(&Y::foo,&Y));
返回0;
}
但它以错误告终。我不确定粘贴整个编译器输出是否合理,但通常

vc11说:

P>错误Cx64:“空STD::(运算符)(μFARG0&,V.00T)const:不能将参数3从“空格”转换为“STD::y*,yd:n:l,sd:::nIL,STD::Y-nIL,STD::S.NIL,STD::Y-NIL> C++:\程序文件(x86)\微软Visual Studio 11 \vc包含\ 1152功能1 1应用程序(微软Visual C++编译器NOV 2012 CTP)<

和g++:

编译已完成,但有错误:
source.cpp:在“X::X(T)[with T=std::_Bind(Y*)>]的实例化中]:
来源:cpp:28:33:此处需要
source.cpp:8:9:错误:调用(std:_Bind_helper(Y*)>),X*常量,std:_Bind(Y*)>&>:类型{aka std:_Bind(Y*)>)>(X*,std:_Bind(Y*)>)>()”

有没有办法解决这个问题。对我来说,保存主要思想非常重要——一个可以用任何可调用对象(函数对象、函数指针或
std::bind()
function返回的调用包装器)实例化的类

如果有人帮忙,我将不胜感激


另外,如果我创建一个传递函数对象或函数指针的
X
实例,它就会编译。

问题的根本原因似乎是由
std::bind
执行的参数的内部复制,特别是
t

您可能希望通过以下方式解决此问题:

  template <typename T>
  explicit X(T t)
  {
      std::bind(&X::invoke<T>, this, std::placeholders::_1)(t);
      //                             ^^^^^^^^^^^^^^^^^^^^^  ^
  }

更新:

上述解决方案是有助于实现示例中显示的内容的变通方法。然而,从评论中可以看出,您的用例可能有很大的不同(例如,将
bind
的结果传递给以后的评估)

正如在他的回答中正确指出的那样,概念上正确的解决方案在于使用Boost的
protect
等结构

如果您不想使用Boost,使用C++11的可变模板定义自己的
protect()
函数非常容易:

// Imitates boost::protect, but with variadic templates and perfect forwarding
namespace detail
{
    template<typename F>
    struct protect
    {
    private:

        F _f;

    public:

        explicit protect(F f): _f(f)
        {
        }

        template<typename... Ts>
        auto operator () (Ts&&... args) -> 
            decltype(_f(std::forward<Ts>(args)...))
        {
            return _f(std::forward<Ts>(args)...);
        }
    };
}

template<typename F>
detail::protect<F> protect(F&& f)
{
    return detail::protect<F>(std::forward<F>(f));
}
//模仿boost::protect,但使用可变模板和完美转发
名称空间详细信息
{
模板
结构保护
{
私人:
F(u)F,;
公众:
显式保护(F):\u F(F)
{
}
模板
自动运算符()(Ts&…args)->
decltype(_f(std::forward(args)…)
{
返回_f(std::forward(args)…);
}
};
}
模板
详细信息::保护(F&&F)
{
返回细节::protect(std::forward(f));
}
最后,正如Maxim所建议的,这就是你如何在课堂上使用它的方法:

class X
{
public:
    template <typename T>
    explicit X(T t)
    {
        auto pt = protect(t);
        std::bind(&X::invoke<decltype(pt)>, this, pt)();
    }
private:
    template <typename T>
    void invoke(T t)
    {
        t();
    }
};
X类
{
公众:
模板
显式X(T)
{
自动pt=保护(t);
std::bind(&X::invoke,this,pt)();
}
私人:
模板
无效调用(T)
{
t();
}
};

我认为他们在
std::bind
中采用它时忽略了
boost::bind
的一个重要部分,即
boost::protect()
。您的代码可以按如下方式修复:

#include <boost/bind/protect.hpp>
// ...
X x(boost::protect(std::bind(&Y::foo, &y)));
#包括
// ...
X(boost::protect(std::bind(&Y::foo,&Y));
或者,或者:

template <typename T>
explicit X(T t)
{
    auto tt = boost::protect(t);
    auto f = std::bind(&X::invoke<decltype(tt)>, this, tt);
    f();
}
模板
显式X(T)
{
自动tt=升压::保护(t);
auto f=std::bind(&X::invoke,this,tt);
f();
}

虽然默认情况下,第一个参数不计算,但所有其他参数都是。有时,不必计算第一个参数之后的参数,即使它们是嵌套的绑定子表达式。这可以通过另一个函数对象protect来实现,该函数对象屏蔽了该类型,使bind无法识别和计算它。调用protect时,protect只是将参数列表转发给另一个未修改的函数对象

header boost/bind/protect.hpp包含一个protect的实现。要保护绑定函数对象不被计算,请使用protect(bind(f,…))


Scott Meyers即将发布的文章将推荐您更喜欢lambdas而不是std::bind。在C++11中,您可以简单地执行以下操作:

template <typename T>
explicit X(T t)
{
    auto f = [t, this]() { this->invoke(t); };
    f();
}
// ...

X x([&y](){ y.foo(); });
模板
显式X(T)
{
自动f=[t,this](){this->invoke(t);};
f();
}
// ...
X([&y](){y.foo();});

在我看来,它解决了一个稍微不同的问题。从某种意义上说,原始绑定表达式是自包含的,它存储所有参数的副本,因此可以销毁这些参数。您的解决方案忽略了复制函子,并依赖于它在调用时仍在作用域中且处于活动状态。实际上,创建绑定表达式然后立即调用它是没有意义的。相反,您希望将bind创建的函子传递到其他地方,并经常将调用延迟到以后。@MaximYegorushkin:确实如此。尽管如此,这仍然是OP用例的有效解决方法。不确定这是否是他的真实用例。请参阅我之前更新的评论。@MaximYegorushkin:我理解你的评论。根据OP提供的示例,这提供了一个变通方法(我使用的就是这个词)。我并不是说这是一个概念上完美的解决方案。特别是在我建议的第一个解决方法中,OP不会被强制立即调用bind的结果;它可以单独复制论点。再说一次,我并不是说这个解决方案是完美的,更不用说比你的更好了,我只是说它提供了一个解决方法。例如,OP可能不想使用boost。谢谢Andy,std::bind(&X::invoke,this,cref(t))()解决了我的问题。如果我打算在ctor中启动一个线程,那么它也会很有用,将invoke()方法绑定为thre
template <typename T>
explicit X(T t)
{
    auto f = [t, this]() { this->invoke(t); };
    f();
}
// ...

X x([&y](){ y.foo(); });