c++ - 为什么(或何时)模板引入其命名空间?

标签 c++ templates namespaces c++17

下面是一个例子:

#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 命名空间带入他的私有(private)命名空间,也不想在每次使用时都为完全限定它而烦恼。
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 实例化的.

关于c++ - 为什么(或何时)模板引入其命名空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64563430/

相关文章:

function - Play 2.0 可重用模板功能与 HTML 正文

c++ 使用包含 <time.h> 和 <ctime> 的 time() - 哪个优先?

c++ - C++ 中的 xvalue 是什么

c++ - Visual Studio13 创建线程和优化流程

ruby - 有没有最新的 Ruby Gems 提供 gem 模板?

c++ - 使用策略模板类工厂创建策略模板类?

windows-phone-7 - 在 Windows Phone 中重命名命名空间

clojure - 如何在测试期间加载/删除 clojure 中的命名空间

C++ - 荒谬的长距离

c++ - 在 MPI 中使用 Armadillo 稀疏矩阵