簡體   English   中英

在B類中聲明為朋友的A類成員模板函數無法訪問A類的私有成員(僅限Clang)

[英]Class A member template function declared as friend in class B can't access private members of class A (Clang only)

請查看此代碼段。 我知道它沒有多大意義,它只是為了說明我遇到的問題:

#include <iostream>
using namespace std;

struct tBar
{
    template <typename T>
    void PrintDataAndAddress(const T& thing)
    {
        cout << thing.mData;
        PrintAddress<T>(thing);
    }

private:
    // friend struct tFoo; // fixes the compilation error

    template <typename T>
    void PrintAddress(const T& thing)
    {
        cout << " - " << &thing << endl;
    }
};

struct tFoo
{
    friend void tBar::PrintDataAndAddress<tFoo>(const tFoo&);
    private:

    int mData = 42;
};

struct tWidget
{
    int mData = 666;
};

int main() 
{
    tBar bar;
    bar.PrintDataAndAddress(tWidget()); // Fine

    bar.PrintDataAndAddress(tFoo()); // Compilation error

    return 0;
}

上面的代碼觸發以下錯誤:

source_file.cpp:10:3​​: 錯誤:'PrintAddress'是'tBar'PrintAddress(thing)的私有成員 ; source_file.cpp:42:6:注意:在實例化函數模板>特殊化'tBar :: PrintDataAndAddress'這里請求bar.PrintDataAndAddress(tFoo()); //編譯錯誤source_file.cpp:17:7:注意:聲明私有這里void PrintAddress(const T&thing)

但僅限於Clang ++。 GCC和MSVC很好用(您可以通過在http://rextester.com/l/cpp_online_compiler_clang中粘貼該代碼來快速測試)

似乎tBar::PrintDataAndAddress<tFoo>(const tFoo&)使用與tFoo相同的訪問tFoo ,在那里它是友好的。 我知道這是因為在tBartFoo建立tBar解決這個問題。 如果tBar::PrintDataAndAddress是非模板函數,問題也會消失。

我無法在標准中找到解釋此行為的任何內容。 我相信這可能是對14.6.5 - temp.inject的錯誤解釋,但我無法聲稱我已經閱讀了所有內容。

有沒有人知道Clang是否正確無法編譯上述代碼? 如果是這樣的話,你能引用相關的C ++標准文本嗎?

似乎要發生這個問題,被訪問的私有成員需要是模板功能。 例如,在上面的例子中,如果我們使PrintAddress成為非模板函數,代碼將編譯沒有錯誤。

在使用之前強制編譯器實例化tBar::PrintDataAndAddress<tFoo>解決了這個問題。

int main() 
{
    tBar bar;
    bar.PrintDataAndAddress(tWidget()); // Fine

    auto x = &tBar::PrintDataAndAddress<tFoo>; // <= make it work....

    bar.PrintDataAndAddress(tFoo()); // Now fine

   return 0;
}

它似乎是一個編譯器promlem,因為它看起來非常相似:

在C ++中,為什么不能使用另一個類的模板類型來管理模板類成員函數?

要更精確一點......在行bar.PrintDataAndAddress(tFoo()); 編譯器必須實現成員函數tBar::PrintDataAndAddress<tFoo> ,同時它必須解析友元聲明。 這是兩個單獨的步驟。 顯然,當編寫一個表達式時,編譯器不會按照嚴格順序執行此操作。 要強制編譯器首先通過訪問函數指針來實例化bar.PrintDataAndAddress(tFoo()) ,這兩個步驟的順序正確。

嘗試在友元功能之前添加此功能

template <typename tFoo>

暫無
暫無

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

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