未考虑与参数相关的查找

argument dependent lookup not considered

本文关键字:查找 参数      更新时间:2023-10-16

为什么依赖于参数的查找不考虑Foo::dynamicCast,难道不应该考虑命名空间Foo吗?因为基类在这个命名空间中?

#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());

为了理解您有一个带有模板的函数调用,而不是一堆<>运算符,编译器必须知道您有一块函数模板;为了理解这一点,它必须知道在哪个命名空间中查找它。为了知道这一点。它必须理解函数参数的命名空间。为了理解,它必须知道周围有函数自变量。正如我们所看到的,这取决于知道一开始就有一个函数调用。编译器直到找到模板声明才知道。看到问题了吗?

因此,只有当函数调用中的后缀表达式是不合格id时,才会考虑ADL。哪个dynamicCast<Test::Derived>而不是<edit>仅当已知dynamicCast模板名称时,该名称是在正常的非限定查找过程中确定的,不查找声明模板的命名空间。

正如@T.C.所观察到的,可以在全局命名空间中声明一个名为dynamicCast的无关函数模板,以使ADL工作。

<编辑>

在一个更好的世界里,我们可以选择在任何上下文中编写template foo<whatever>,并消除尖括号的歧义。也许在C++20中。

通过ADL找不到具有显式模板参数的模板函数。也许是解析问题,不知道为什么。

另一个例子是CCD_ 8。如果没有using语句,就无法get<3>(some_tuple)

您可以通过将作为模板参数传递的参数作为标记类型来解决此问题。你也可以做一个两步的外部函数加上内部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

我没有章节和诗句的标准为你。