我正在尝试创建一个在 std::bind 之前匹配的网络绑定函数

I'm trying to make a networking bind function which matches before std::bind

我正在开发一个 C++ 库,它是一种 higher-level 套接字接口。这个想法是使用相同的函数名称进行类似的调用,但具有更清晰的界面和更好的类型安全性。这意味着我有自己的(网络)绑定函数,它的签名类似于:

void MySocketLib::bind(const MySocketLib::MySocket &s, const MySocketLib::MyEndpoint &e);

其中 MySocketLib 是命名空间。这一切都很好,只要你打电话

MySocketLib::bind(s,e);

当 s 和 e 具有匹配类型时。但是,如果你这样做:

#include <functional>
#include "mysocketlib.h"
using namespace std;
using namespace MySocketLib;
...
bind(s,e);

然后,绑定在函数中获取 std::bind。我总是可以只调用 MySocketLib::bind(s,e),但我更希望 un-qualified 调用选择 MySocketLib::bind 函数而不是 std::bind 模板。这是使用 gnu g++。

std::bind 和 ::bind 之间的 similar problem 似乎已在 gcc headers 中得到解决。但这并不能解决我的问题,因为我的套接字不是整数。

我试过的是创建一个专业,像这样:

namespace std {
template<>
void bind(const MySocketLib::MySocket &s, const MySocketLib::MyEndpoint &e) {
    MySocketLib::bind(s,a);
} }

但是它告诉我我的 bind(...) 不匹配任何模板声明。 (下面是完整的编译器消息)。即使这些是它愉快地实例化的调用中的确切类型 std::bind。我想要的是一些关于我到底如何专门化 std::bind 的建议,或者一些其他方法来完成使普通 bind() 在使用两者时引用 MySocketLib::bind 而不是 std::bind命名空间。

以下是 g++ 对我的专业化失败的完整编译器诊断。任何建议表示赞赏。

In file included from mysocketlib.cpp:12:0:
mysocketlib.h:330:6: error: template-id 'bind<>' for 'void std::bind(const MySocketLib::MySocket&, const MySocketLib::MyEndpoint&)' does not match any template declaration
 void bind(const MySocketLib::MySocket &s, const MySocketLib::MyEndpoint &a) {
      ^~~~
In file included from mysocketlib.h:323:0,
                 from mysocketlib.cpp:12:
/usr/include/c++/7/functional:899:5: note: candidates are: template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^~~~
/usr/include/c++/7/functional:875:5: note:                 template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...)
     bind(_Func&& __f, _BoundArgs&&... __args)
     ^~~~

请参阅上面的评论,为什么这是设计类似于 "customers keep on knocking the bottom floor off my buildings, and the upper floors fall down. How can I ensure the top floors still stand when the bottom floor is knocked out?"

的解决方案

std::bind 是使用 varardic 转发模板实现的。

namespace MySocketLib {
  namespace details {
    void my_socket_bind(const ::MySocketLib::MySocket &s, const ::MySocketLib::MyEndpoint &e);
  }
  template<class S0, class S1,
    std::enable_if_t<
      std::is_same< std::decay_t<S0>, MySocket >{}
      && std::is_same< std::decay_t<S1>, EndPoint >{}
    , bool> = true
  >
  void bind(S0&&s, S1&e) {
    return details::my_socket_bind( s, e );
  }
}

这是脆弱的、神秘的,但当将两者导入同一范围时,应将您的 bind 置于任何 std::bind 之上或之上。

您实施 MySocketLib::details::my_socket_bind.

:

enable_if_t<...> 可能需要替换为 typename enable_if<...>::type

is_same<...>{} 可能需要替换为 is_same<...>::value

尽管我的 SFINAE 代码符合 标准,但一些较旧的编译器可能会卡住。有很多替代方案,哪些有效取决于具体的编译器。