[英]ADL cannot find overloaded function
template<typename T>
struct S
{
bool valid(T a)
{ return is_valid(a); }
};
bool is_valid(int)
{ return true; }
int main()
{
S<int> s;
s.valid(0);
}
VS可以很好地編譯此樣本,而GCC則表示:
錯誤:在此范圍內未聲明'is_valid',並且在實例化點[-fpermissive]依賴於參數的查找未找到任何聲明
我不確定為什么ADL找不到在S<int> s
實例化之前定義的bool is_valid(int)
。 我想這是正確的行為,就像Clang所說的一樣。 所以我嘗試添加
template<typename T>
bool is_valid(T);
剛開始使用函數重載,現在Godbolt通過Clang或GCC對其進行了很好的編譯 ,但對本地GCC編譯或在Ideone上沒有進行過編譯。
在這種情況下,如何在模板聲明(GCC)之后使用ADL提供函數定義? 獎勵:為什么Godbolt會編譯最后一個樣本?
多虧了已接受的答案,我才發現問題在於ADL特別對待原始類型。 這幫助我最終得到了以下解決方案,該解決方案使用模板化函數的前向聲明,該函數對於用戶定義的類型而言可以重載,或者對於原始類型可以專門化。
template<typename T>
bool is_valid(T);
template<typename T>
struct S
{
bool valid(T a)
{ return is_valid(a); }
};
template<>
bool is_valid<int>(int)
{ return true; }
struct User_data
{};
bool is_valid(User_data)
{ return true; }
int main()
{
S<int> s_primitive;
s_primitive.valid(0);
S<User_data> s_user_data;
s_user_data.valid(User_data{});
}
解決方案是轉發聲明is_valid(int)
:
bool is_valid(int);
template<typename T>
struct S
{
bool valid(T a)
{ return is_valid(a); }
};
基本類型(如int
)的ADL會生成一組空的名稱空間和要考慮的類,因此,當您將0
傳遞給S::valid
,就不會引入外部的is_valid(int)
。 前向聲明有效地使模板知道該函數存在。
關於您在Godbolt中看到的行為...編譯器資源管理器必須完成一些額外的工作,因為據稱所使用的相同gcc和clang版本不適用於任何其他編譯器(例如Wandbox)
如果您確實希望ADL工作,則需要修改自由函數is_valid
,以便可以選擇ADL。 我的建議是在與所有自由浮動的is_valid
函數相同的范圍內聲明一個輔助結構ADL_Helper
,然后S::is_valid
將傳遞一個實例:
struct ADL_Helper{};
template<typename T>
struct S
{
bool valid(T a)
{ return is_valid(a, ADL_Helper{}); }
};
bool is_valid(int, ADL_Helper)
{ return true; }
int main()
{
S<int> s;
s.valid(0);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.