簡體   English   中英

ADL找不到重載函數

[英]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{});
}

Wandbox

解決方案是轉發聲明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.

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