std::bind绑定std::shared_ptr::operator*在MSVC编译失败,是bug还是可修复?
问题
以下C代码可在g 8.1.0和clang 10.0.0环境下正常编译:
#include <memory> #include <iostream> #include <functional> int main() { auto dereference = std::bind( &std::shared_ptr<int>::operator*, std::placeholders::_1); std::shared_ptr<int> sp = std::make_shared<int>(10); std::cout << dereference(sp) << std::endl; return 0; }
但在VS2022的MSVC编译器中,会报出如下错误:
example.cpp<source>(6): error C2672: 'std::bind': no matching overloaded function found C:/data/msvc/14.34.31931-Pre/include\functional(2029): note: could be 'std::_Binder<_Ret,_Fx,_Types...> std::bind(_Fx &&,_Types &&...)' <source>(8): note: 'std::_Binder<_Ret,_Fx,_Types...> std::bind(_Fx &&,_Types &&...)': could not deduce template argument for '_Ret' <source>(8): note: 'std::_Binder<_Ret,_Fx,_Types...> std::bind(_Fx &&,_Types &&...)': could not deduce template argument for '_Fx' C:/data/msvc/14.34.31931-Pre/include\functional(2024): note: or 'std::_Binder<std::_Unforced,_Fx,_Types...> std::bind(_Fx &&,_Types &&...)' <source>(8): note: 'std::_Binder<std::_Unforced,_Fx,_Types...> std::bind(_Fx &&,_Types &&...)': could not deduce template argument for '_Fx' <source>(11): error C3536: 'dereference': cannot be used before it is initialized <source>(11): error C2064: term does not evaluate to a function taking 1 arguments Compiler returned: 2
请问这是MSVC编译器的bug,还是上述代码可以修复?
解答
这不是MSVC的bug,代码可以修复。问题出在std::shared_ptr<int>::operator*的重载上——这个成员函数有const和非const两个版本,当直接取地址&std::shared_ptr<int>::operator*时,MSVC无法自动推导要绑定的是哪个重载版本,而GCC和Clang在这种场景下做了额外的推导兼容。
修复方法有两种:
- 显式指定重载版本的类型:通过强制类型转换明确告诉编译器要绑定的是哪个版本的
operator*,通常选择const版本适用性更广:
auto dereference = std::bind( static_cast<int& (std::shared_ptr<int>::*)() const>(&std::shared_ptr<int>::operator*), std::placeholders::_1);
- 改用lambda表达式替代std::bind:lambda的可读性和兼容性更好,完全避免重载推导问题,还能简化代码:
auto dereference = [](const std::shared_ptr<int>& sp) -> int& { return *sp; };
或者更通用的版本:
auto dereference = [](const auto& sp) -> decltype(auto) { return *sp; };
内容的提问来源于stack exchange,提问作者syby119
相关产品推荐
相关产品推荐

