为什么依赖于参数的查找不考虑Foo::dynamicCast
,不应该考虑名称空间Foo,因为Base类在此命名空间中?
#include <memory>
using namespace std;
namespace Foo
{
template<typename P, typename T> P*
dynamicCast(T* t)
{
return dynamic_cast<P*>(t);
}
class Base
{
public:
virtual ~Base() = default;
};
}
namespace Test
{
class Derived : public Foo::Base
{
};
}
shared_ptr<Foo::Base> b = make_shared<Test::Derived>();
auto d = dynamicCast<Test::Derived>(b.get());
答案 0 :(得分:4)
为了甚至理解你有一个模板的函数调用,而不是一堆<
和>
运算符,编译器必须知道你有一个函数模板;并且为了理解它,它必须知道要查找的命名空间。并且为了知道它,它必须理解函数参数的命名空间。并且为了理解 它必须知道是函数参数。正如我们所看到的,这取决于知道有一个函数调用开始。在找到模板声明之前,编译器不知道哪个。看到问题了?
因此,只有在函数调用中的postfix-expression是 unqualified-id 时才会考虑ADL。仅当dynamicCast<Test::Derived>
已知为模板名称时,哪个dynamicCast
不 &lt; edit&gt; 在正常的非限定查找期间确定,该查找不会查看声明模板的命名空间。
As @ T.C。观察到,可以在全局命名空间中声明一个名为dynamicCast
的无关函数模板,以使ADL工作。
&lt; / edit&gt;
在一个更美好的世界中,我们可以选择在任何上下文中编写template foo<whatever>
并消除尖括号的歧义。也许在C ++ 20中。
答案 1 :(得分:3)
通过ADL找不到具有显式模板参数的模板函数。也许解析问题,不知道为什么。
另一个例子是std::get
。没有使用声明,你不能get<3>(some_tuple)
。
您可以通过将作为模板args传递的参数作为标记类型传递来解决此问题。您还可以执行一步两步的外部函数以及内部ADL标记调度查找(因此必须限定公共函数,但可以完成基于内部标记的ADL的自定义点)。
// tag utilities:
template<class T>struct tag_t{using type=T;constexpr tag_t(){};};
template<class T>constexpr tag_t<T> tag={};
namespace some{
template<class T, class U>
T* dynamic(tag_t<T>, U* u){
return dynamic_cast<T>(u);
}
struct bob{};
}
现在dynamic(tag<int>,new some::bob{})
将通过ADL找到dynamic
。
我没有标准的章节和经文。