簡體   English   中英

為什么 ADL 不能使用 std::get 解析為正確的函數

[英]Why ADL does not resolve to the correct function with std::get

我正在嘗試編寫一個模板函數,該函數使用 ADL 解析的get來獲取結構/范圍( tuple -esque)的成員。

#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 發生?

問題最終是模板:

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

那時,編譯器還不知道這是一個需要使用 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 ,因此它避免了需要具有來自 [dcl.struct.bind] 的名為get的已經可見的函數模板:

通過類成員訪問查找在E的范圍內查找unqualified-id get ,如果找到至少一個聲明,則初始值設定項為e.get<i>() 否則,初始值設定項是get<i>(e) ,其中get在關聯的命名空間中查找。 在任何一種情況下, get<i>被解釋為template-id [ 注意:不執行普通的不合格查找。 — 尾注 ]

筆記是關鍵。 如果我們執行了不合格的查找,我們就會失敗。

對於給出顯式模板參數的函數模板,參數相關查找的工作方式不同。

雖然通過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 查找(即僅在關聯的命名空間中查找)發生:

  • 如果成員查找失敗,則由 range-for 循環執行的非成員函數的查找開始和結束
  • 從模板實例化的角度進行依賴名稱查找。
  • 非成員函數的查找由類似元組類型的結構化綁定聲明執行

添加了重點

快進到 C++20

被 C++20 接受的p0846r0現在允許 ADL 調用帶有顯式模板參數的模板函數。

所以 OP 的代碼現在可以像 C++20 一樣編譯,沒有錯誤!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM