2015-11-25 56 views
4

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

测试了一下。这可以工作:http://ideone.com/tX3JcU – bolov

+0

使用显式模板参数时不会触发ADL。 – 0x499602D2

+2

@ 0x499602D2:稍微复杂一点:除非有一个可见的同名函数模板:[Demo](http://coliru.stacked-crooked.com/a/15b614250f6ad61c)。 – Jarod42

回答

3

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

另一个例子是std::get。没有使用声明,您不能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

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

+0

我猜'U /] * u'是你的手在键盘上睡着了吗? – Barry

+0

@巴里胖手机的手指。 – Yakk

+0

令我印象深刻的是,您可以在手机上输入所有内容! – Barry

4

为了甚至能够理解你有一个模板函数调用,而不是一堆<>运算符,编译器必须知道你有一个函数模板;为了理解这一点,它必须知道要查找哪个命名空间。为了了解它,它必须理解函数参数的命名空间。并且为了了解它必须知道函数的参数。正如我们所看到的,它依赖于知道有一个函数调用开始。编译器在找到模板声明之前不知道的内容。看到问题了吗?

因此,只有在函数调用中的后缀表达式是未限定标识时才会考虑ADL。这dynamicCast<Test::Derived><编辑>只有dynamicCast被称为是一个模板名称,这是正常的不合格查找,不考虑对于模板声明的名称空间中确定。

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

< /编辑>

在一个更美好的世界,我们会写在任何情况下template foo<whatever>和澄清对尖括号的选项。也许在C++ 20中。

+0

'dynamicCast '**是** an * unqualified-id *,**如果**'dynamicCast'是* template-name *。一个'template void dynamicCast()= delete;'通过正常的非限定查找来获取就足以使ADL工作。 –

+0

@ T.C。你当然是对的,我的std :: fu今天很慢。 –