不考虑参数依赖查找

时间:2015-11-25 16:38:10

标签: c++ templates argument-dependent-lookup

为什么依赖于参数的查找不考虑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());

2 个答案:

答案 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

我没有标准的章节和经文。