2017-08-03 26 views
13

我試圖編寫一個模板函數,使用ADL解決get來獲取結構/範圍的成員(tuple -esque)。爲什麼ADL不解析爲正確的函數與std ::得到

#include <iostream> 
#include <utility> 
#include <tuple> 

int main() { 
    auto tup = std::make_tuple(1, 2); 
    std::cout << get<0>(tup) << std::endl; 
} 

我做的原因是什麼結構化綁定提案(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf§11.5.3)表示,有關如何get被用來獲取的結構元素這一點。它表示非會員get用於從結構中獲取元素。

我認爲上面的代碼將編譯,因爲ADL會導致std命名空間來看待爲get功能(因爲它的參數是std::tuple<int, int>類型,這是在std的),它會被發現。但是,我收到一個錯誤。有人可以在這裏解釋正確的方法,以及爲什麼上面的代碼不起作用?在這種情況下,如何迫使ADL發生?

回答

12

問題最終是模板:

std::cout << get<0>(tup) << std::endl; 
//   ~~~~ 

此時,編譯器不知道這是一個需要t o使用ADL查找 - get只是一個名字。由於這個名字本身並沒有找到任何東西,這將被解釋爲一個未知的名字,然後是小於。爲了得到這個工作,你需要一些其他的功能模板get可見:

using std::get; 
std::cout << get<0>(tup) << std::endl; // now, OK 

即使什麼都不做:

template <class T> void get(); 

int main() { 
    auto tup = std::make_tuple(1, 2); 
    std::cout << get<0>(tup) << std::endl; 
} 

結構化結合措辭明確查找get使用參數相關的查找,所以它避免了需要有一個名爲get已經可見函數模板,從[dcl.struct.bind]:

ü通過類成員訪問查找,在E的範圍內查找nqualified-idget,如果發現至少有一個聲明,則初始化程序爲e.get<i>()。否則,初始化程序是get<i>(e),其中get在關聯的名稱空間中查找。在任一情況下,get<i>被解釋爲模板ID。 [注:普通的不合格查找不執行。 - 尾註]

注意事項是關鍵。如果我們執行了不合格的查找,那麼我們就會失敗。

+0

非常有趣!我不知道,引入這個未定義的函數可能會導致其他問題嗎?像衝突之類的? – Curious

+0

@Curious它會,如果它最終成爲首選。我的意思是,實際上不這樣做 - 我只是爲了解釋目的而放在那裏。 – Barry

+0

嗯,有什麼辦法可以強迫ADL發生?我嘗試了'template'關鍵字,但當然不起作用。 – Curious

11

參數依賴查找不能以相同的方式工作for function templates where an explicit template argument is given

儘管函數調用能夠通過即使普通 查找發現什麼都沒有,一個函數調用與 顯式指定的模板參數的函數模板ADL解決需要有一個 聲明模板的普通發現查找(否則,它是 一個語法錯誤遇到未知名後跟一個小於 字符)

基本上,需要有某種方式讓不合格的查找找到一個模板函數。然後,ADL可以踢(因爲名稱get然後被稱爲模板)。 Cppreference舉了一個例子:

namespace N1 { 
    struct S {}; 
    template<int X> void f(S); 
} 
namespace N2 { 
    template<class T> void f(T t); 
} 
void g(N1::S s) { 
    f<3>(s);  // Syntax error (unqualified lookup finds no f) 
    N1::f<3>(s); // OK, qualified lookup finds the template 'f' 
    N2::f<3>(s); // Error: N2::f does not take a non-type parameter 
       //  N1::f is not looked up because ADL only works 
       //    with unqualified names 
    using N2::f; 
    f<3>(s); // OK: Unqualified lookup now finds N2::f 
      //  then ADL kicks in because this name is unqualified 
      //  and finds N1::f 
} 

結構綁定是一種特殊情況下,啓用了ADL。

在以下上下文中ADL-僅查找(即,在僅 相關聯的命名空間查找)發生:

  • 非成員的查找函數開始和結束由範圍換進行如果成員查找失敗,則循環
  • 從模板實例化角度查找相關名稱。
  • 非成員函數的查找得到由結構化的綁定聲明爲元組樣類型執行

着重強調

+0

它會工作說'std :: cout << template得到<0>(tup)<<'\ n'',或者是否有一個明確的'模板'由於某種原因不能在那裏工作嗎? –

+0

@DanielH這聽起來像*可以*如果有人提出它的工作。它[此刻不工作](https://wandbox.org/permlink/dmG6fVeDQwzHvl6q) – Justin

+0

感謝您的回答。我想接受這兩個答案,但因爲其他答案包括一個簡單解析技術的簡單例子。我會接受這一點。 – Curious

相關問題