2015-11-25 59 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今天很慢。 –