【发布时间】:2015-08-26 20:07:24
【问题描述】:
这与this question 非常相似,但我不确定那里的答案是否完全适用于我编写的用于演示该问题的最少代码。 (我的代码不使用尾随返回类型,并且还有一些其他差异。)此外,MSVC 的行为是否合法的问题似乎没有得到解决。
简而言之,当函数模板位于命名空间内时,我看到编译器选择通用函数模板实例化而不是更具体的重载。
考虑以下一组命名空间和类定义:
namespace DoStuffUtilNamespace
{
template<typename UNKNOWN>
void doStuff(UNKNOWN& foo)
{
static_assert(sizeof(UNKNOWN) == -1, "CANNOT USE DEFAULT INSTANTIATION!");
}
}
class UtilForDoingStuff
{
public:
template <typename UNKNOWN>
void doStuffWithObjectRef(UNKNOWN& ref)
{
DoStuffUtilNamespace::doStuff(ref);
}
};
class MyClassThatCanDoStuff { };
namespace DoStuffUtilNamespace
{
using ::MyClassThatCanDoStuff; // No effect.
void doStuff(MyClassThatCanDoStuff& foo) { /* No assertion! */ }
}
...以及以下用例:
int main()
{
MyClassThatCanDoStuff foo;
DoStuffUtilNamespace::MyClassThatCanDoStuff scoped_foo;
UtilForDoingStuff util;
DoStuffUtilNamespace::doStuff(foo); // Compiles
DoStuffUtilNamespace::doStuff(scoped_foo); // Compiles
util.doStuffWithObjectRef(foo); // Triggers static assert
util.doStuffWithObjectRef(scoped_foo); // Triggers static assert
}
如果整个 DoStuffUtilNamespace 被消除并且它的所有成员都被移动到全局范围内,这可以用 G++ 和 Clang++ 很好地编译。
有了命名空间,doStuff当然是一个从属名。根据top-voted answer on the similar question,标准说:
在解析从属名称时,会考虑来自以下来源的名称:
在模板定义处可见的声明。
来自与函数参数类型相关的命名空间的声明,来自实例化上下文和定义上下文。
这对我来说有点奇怪;我不明白为什么第一个要点会指定声明必须在模板的 definition 处可见,而不是在 instantiation 处可见,因为第二个要点明确指定一些声明仅在实例化点可见是允许的。 (如果有人想提供一个理由,我会很感激,但这不是我的问题,因为我的理解是“标准委员会为什么决定 X”形式的问题是题外话。)
所以我认为这解释了为什么util.doStuffWithObjectRef(foo); 触发静态断言:doStuff(MyClassThatCanDoStuff&) 尚未在UtilForDoingStuff::doStuffWithObjectRef<UNKNOWN>(UNKNOWN&) 的定义点被声明。确实,在定义doStuff 重载之后移动class UtilForDoingStuff 定义似乎可以解决问题。
但标准中“与函数参数类型相关的命名空间”究竟是什么意思? using ::MyClassThatCanDoStuff 声明不应该与命名空间内scoped_foo 实例类型的显式作用域一起触发依赖于参数的查找,并且该查找不应该找到doStuff() 的非断言定义吗?
此外,使用 clang++ -ftemplate-delayed-parsing 模拟 MSVC 的模板解析行为,编译整个代码时不会出错。至少在这种特殊情况下,这似乎更可取,因为随时向命名空间添加新声明的能力是命名空间的主要吸引力之一。但是,如上所述,根据标准,它似乎并不完全符合法律条文。这是允许的,还是不合格的实例?
EDIT:: 正如 KIIV 所指出的,有一个解决方法;如果使用模板特化而不是重载,则代码编译。我仍然想知道有关标准的问题的答案。
【问题讨论】:
标签: c++ templates namespaces argument-dependent-lookup