11

最近我发现shared_ptr没有指向成员运算符的指针->*。我创建了一个简单的例子:

template <typename Pointer, typename Function, typename... Args>
auto invoke1(Pointer p, Function f, Args... args) -> decltype((p->*f)(args...))
{
  return (p->*f)(args...);
}
struct A { 
    void g() { std::cout << "A::g()\n"; } 
};
int main() {
  A a;
  invoke1(&a, &A::g); // works!!
  std::shared_ptr<A> sa = std::make_shared<A>();
  invoke1(sa, &A::g); // compile error!!
}

Q1:为什么会这样?为什么 shared_ptr 没有这个操作符?

我添加了这样的运算符,shared_ptr示例开始工作:

template <typename T, typename Result>
auto operator ->* (std::shared_ptr<T> pointer, Result (T::*function)()) ->decltype(std::bind(function, pointer))
{
    return std::bind(function, pointer);
}
template <typename T, typename Result, typename Arg1>
auto operator ->* (std::shared_ptr<T> pointer, Result (T::*function)(Arg1 arg1)) ->decltype(std::bind(function, pointer, std::placeholders::_1))
{
    return std::bind(function, pointer, std::placeholders::_1);
}

Q2:这个运营商的实施是否正确?是否有任何“黄金”规则如何实施这样的运营商,可能我重新发明了轮子或完全错误的方向,你怎么看?有没有办法让一个函数实现这个运算符,而不是像标准中的占位符一样多的函数......

之后,我得出结论,std::bind可以在我的invoke方法中使用。

template <typename Pointer, typename Function, typename... Args>
auto invoke2(Pointer p, Function f, Args... args) 
                     -> decltype(std::bind(f, p, args...)())
{
   return std::bind(f, p, args...)();
}

这样,我的示例也无需添加operator ->*shared_ptr.

Q3:那么,std::bind现在被认为是替代品operator->*吗?

4

3 回答 3

6

简而言之:是的 std::bind 是成员函数指针的替代品。

为什么?因为成员函数指针很糟糕,它们的唯一目的是实现委托,这就是 std::bind 和 std::function 这样做的原因

有关如何实现成员函数指针的参考,请参阅我之前的答案。简单来说,成员函数指针被标准削弱了,因为它们不允许在强制转换后调用;这使得它们对于 90% 的人希望从成员函数指针中获得的那种行为毫无意义:委托。

出于这个原因,std::function 用于表示抽象的“可调用”类型,std::bind 用于将 this 绑定到成员函数指针。你绝对不应该弄乱成员函数指针,而应该使用 std::bind 和 std::function。

于 2014-02-01T02:15:14.103 回答
4

我相信最简单的方法是->用一对 derefence( *) 和结构引用( .) 运算符替换“结构取消引用”() 运算符:

template <typename Pointer, typename Function, typename... Args>
auto invoke1(Pointer p, Function f, Args... args) -> decltype(((*p).*f)(args...))
{
  return ((*p).*f)(args...);
}
于 2014-01-31T18:34:25.570 回答
2

我相信shared_ptr没有运算符->*,因为不可能为任意数量的参数实现它(C++11 允许为其他用例做)。invoke此外,您可以轻松地为调用 的智能指针添加函数重载get(),因此不希望使接口复杂化。

于 2013-07-18T16:16:00.873 回答