c++ - 为什么(或何时)模板引入其命名空间?
问题描述
这是一个例子:
#define MAKE_IT_WORK false
namespace Bob { // Bob's project namespace
struct DeviceFrequency {};
extern void debugf(const char* fmt, ...);
} // namespace Bob
namespace SSN { // Super-Secret Namespace
namespace debugging {
extern int ssn_debug;
extern void debugf(const char* fmt, ...);
} // namespace debugging
} // namespace SSN
namespace SSN::signals { // Super-Secret Namespace, project signals
template<typename Coder> // In the example, this imports Bob's namespace
class Frequency {
public:
Frequency( void )
{ using namespace ::SSN::debugging; // Why isn't this enough??
using ::SSN::debugging::debugf; // Or this??
if( ssn_debug )
#if MAKE_IT_WORK
::SSN::debugging:: // How can a developer predict that this is needed??
#endif
debugf("Frequency(%p,%zd)::Frequency\n", this, sizeof(*this));
}
}; // class Frequency
} // namespace SSN::signals
struct Controller {
SSN::signals::Frequency<Bob::DeviceFrequency> bobcon;
Controller( void ) : bobcon() {}
}; // class Controller
在此示例中,Bob 复制了该debugf
函数,因为他不想将整个 SSN 名称空间带入他的私有名称空间,也不想在每次使用它时都为完全限定它而烦恼。
SSN 开发人员没有意识到模板也可以导入其名称空间(直到它发生),显然使 ADL 查找发挥了作用。尽管 ADL 查找声明命名空间中的 using 语句被忽略,但它为什么发挥作用根本没有意义。一个命名空间无意中污染另一个命名空间似乎太容易了,而且很难预测有朝一日这可能会发生在内联代码中的什么地方。
看起来(至少)每当在命名空间中使用模板时,每个命名空间函数引用都必须是完全限定的,因为在使用模板时,您无法预测何时可能会发生名称冲突。它是否正确?如果是这样,有什么方法可以避免所有似乎需要的额外名称限定符输入?这种暴露是否仅限于模板,还是所有导入的内联代码都以某种方式同样容易受到攻击?
使用 gcc 版本 10.2.0 和 10.2.1 (Red Hat 10.2.1-5) 编译 (Dirty.cpp),我收到以下消息:
make dirty c++ -o Dirty.o -c S/Dirty.cpp -D_CC_GCC -D_OS_BSD -D_HW_X86 -D_OS_LINUX -IS -IH -g -O3 -finline->functions -std=gnu++17 -Wall -Wextra -Wmissing-declarations -Wswitch-default -Werror S/Dirty.cpp: In instantiation of ‘SSN::signals::Frequency<Coder>::Frequency() [with Coder = Bob::DeviceFrequency]’: S/Dirty.cpp:146:32: required from here S/Dirty.cpp:139:12: error: call of overloaded ‘debugf(const char [30], SSN::signals::Frequency<Bob::DeviceFrequency>*, long unsigned int)’ is ambiguous 139 | debugf("Frequency(%p,%zd)::Frequency\n", this, sizeof(*this)); | ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ S/Dirty.cpp:124:13: note: candidate: ‘void SSN::debugging::debugf(const char*, ...)’ 124 | extern void debugf(const char* fmt, ...); | ^~~~~~ S/Dirty.cpp:117:13: note: candidate: ‘void Bob::debugf(const char*, ...)’ 117 | extern void debugf(const char* fmt, ...); |
(已编辑:该示例已恢复为原始示例,现在由@1201ProgramAlarm 重新格式化。出现了一个修改版本,测试示例如下面的部分答案。)
解决方案
对于模板,ADL 包括与为模板类型参数提供的模板参数类型相关的命名空间和实体。因为调用debugf
包含this
作为参数,所以 ADL 将包含namespace Bob
,因为模板是用Bob::DeviceFrequency
.
推荐阅读
- javascript - 自定义我的谷歌地图信息窗口内容
- r - R中不同版本的GlobalOptions包
- python - python根据字符串表示将元组添加到列表中
- java - Java swing 很容易,但我不知道
- sql - 如何从 SQL *PLUS 中的批量插入中查找失败的插入语句
- .net - 如何为登录用户获取 Microsoft Graph 的访问令牌?
- css - CSS Grid min-content 不适合内容
- javascript - JavaScript 可以运行从服务器发送给它的代码吗?
- python - Pandas 中的并行字符串替换
- java - JDBC在android模拟器中工作但不在真实设备上?