关于shared_ptr和指向成员运算符 '->*' 和 'std::bind ' 的指针
About shared_ptr and pointer to member operator `->*` and `std::bind`
最近我发现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->*
的替代品吗
在坚果外壳中:yes std::bind是成员函数指针的替代品
为什么,因为成员函数指针很糟糕,它们的唯一目的是实现委托,这就是为什么std::bind和std::function做
关于如何实现成员函数指针的参考,请参阅我之前的回答。最简单地说,成员函数指针被标准破坏了,因为它们不允许在强制转换之后进行调用;这使得它们对于90%的人希望从成员函数指针中得到的行为来说毫无意义:委托。
因此,std::函数用于表示一个抽象的"可调用"类型,std::bind用于将this绑定到成员函数指针。您绝对不应该使用成员函数指针,而应该使用std::bind和std::function。
我认为最简单的方法是用一对去围栏(*
)和结构引用(.
)运算符替换"结构去引用"(->
)运算符:
template <typename Pointer, typename Function, typename... Args>
auto invoke1(Pointer p, Function f, Args... args) -> decltype(((*p).*f)(args...))
{
return ((*p).*f)(args...);
}
我相信shared_ptr
没有运算符->*
,因为它不可能为任意数量的参数实现(C++11允许为其他用例实现)。此外,您可以很容易地为调用get()
的智能指针添加invoke
函数的重载,因此不希望使接口复杂化。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 是std :: set&lt; std :: future&gt;不可能存在
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- 使用 std::vector<boost::shared_ptr<Base_Class>> 或 boost::p tr_vector 的性能注意事项是什么<Base>
- std::map<std::set, double> AND std:<long>map< std::p air<long, long>, double>
- 如何获取std::vector<DMatch>