【发布时间】:2018-06-12 21:05:34
【问题描述】:
我正在开发一个 C++ 库,它是一种高级套接字接口。这个想法是使用相同的函数名称进行类似的调用,但具有更清晰的接口和更好的类型安全性。这意味着我有自己的(网络)绑定函数,它的签名类似于:
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),但如果非限定调用拾取 MySocketLib::bind 函数而不是 std::bind 模板,我会更喜欢。这是使用 gnu g++。
似乎 std::bind 和 ::bind 之间的 similar problem 已在 gcc 标头中解决。但这并不能解决我的问题,因为我的套接字不是整数。
我尝试过创建一个专业化,如下所示:
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)
^~~~
【问题讨论】:
-
也许你应该花点时间阅读Why is “using namespace std” considered bad practice? 它对其他命名空间也基本有效,不要盲目地去
using它们(甚至不是你自己的)。 -
我认为问题是如何防止不遵循该建议的图书馆用户。
-
@SornelHaetir 我认为你不应该这样做。如果用户想射他或她自己的脚,那么你让他或她去做。如果您提供库,则按原样提供库。图书馆的用户可以正确使用它,这不是真正应该甚至可以强制的东西。
-
主要目标是创建一个类似于普通 C 套接字的接口,但具有较少的怪异和地雷,特别是供网络学生使用。使用命名空间是人们会做的事情,但它会默默地失败。代码编译、运行时不会生成任何运行时消息或异常,并且不会发生预期的网络绑定。真的不会
-
@TWBennet 如果你想通过将所有符号填充到全局符号中来支持忽略命名空间的人,那么你必须使用 C 风格的命名,并为整个项目中的所有项目赋予一个全局唯一的名称世界。所以它变成了
namespace MySocketLib { template<> MySocketLib_notanamespacecoloncolon_bind。现在usingnamespace MySocketLib;` 和using namespace std;的用户将不再发生名称冲突。是的,这很愚蠢,并且消除了命名空间的全部意义,但这就是您所要求的。你也可以使用一个不那么难看的名字。