2020年12月22日火曜日

[C++] Clang ではオーバーロードされた private 関数に明示的な実体化時のアクセスができない?

※この記事は C++ Advent Calendar 2020 22日目の記事です。

はじめに

過去に本ブログでも紹介した template の明示的実体化時に private メンバーアクセス可能な仕様を利用した private メンバー変数・関数へのアクセスですが、最近それを使っていて clang だけとある条件でアクセスできないことに気づきました。

この挙動が仕様として正しいのか正しくないのかは筆者ではわからないので、実挙動ベースの話になってしまいますことをご了承ください。

過去の記事

ブログズミ: [C++] Private な関数のテスト
ブログズミ: [C++] 本当に private なところ

サンプルコード

こちらは iutest の private メンバーのテストのための機能を使ったサンプルです。
Wandbox 用に圧縮したソースコードを使ってますので、実装を確認したい場合はこちらを御覧ください。
https://github.com/srz-zumix/iutest/blob/master/include/iutest_prod.hpp#L62

#define IUTEST_USE_MAIN
#include "iutest.hpp"

class A
{
public:
    int GetX(void) { return m_x; }
private:
    int m_x;
};

IUTEST_MAKE_PEEP(int A::*, A, m_x);

IUTEST(Peep, Test1)
{
    A a;
    IUTEST_PEEP_GET(a, A, m_x) = 42;
    IUTEST_EXPECT_EQ(42, a.GetX());
    IUTEST_EXPECT_EQ(42, IUTEST_PEEP_GET(a, A, m_x));
}

IUTEST(Peep, Test2)
{
    A a;
    IUTEST_PEEP(A, m_x) x(&a);
    x = 54;
    IUTEST_EXPECT_EQ(54, a.GetX());
    x += x;
    IUTEST_EXPECT_EQ(108, a.GetX());
    IUTEST_EXPECT_EQ(108, x);
}

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
https://wandbox.org/permlink/2ZPvpUz1zDe1KHHs

ポイントは IUTEST_MAKE_PEEP と IUTEST_PEEP_GET です。
IUTEST_MAKE_PEEP で private メンバーアクセスするための情報をセットアップし、IUTEST_PEEP_GET で実インスタンスの private メンバーへの R/W を実現しています。

問題のコード
class Hoge
{
    int x;
public:
    Hoge() : x(42) {}
private:
    int GetX() { return x; }
    
private:
    int gX() { return x; }
    int gX() const { return x; }
    int gX(int) { return x; }
};


IUTEST_MAKE_PEEP(int (Hoge::*)(), Hoge, GetX);
IUTEST_MAKE_PEEP(int (Hoge::*)(), Hoge, gX);

int main()
{
    Hoge hoge;
    std::cout << IUTEST_PEEP_GET(hoge, Hoge, GetX)() << std::endl;
    std::cout << IUTEST_PEEP_GET(hoge, Hoge, gX)() << std::endl;
}

Clang の場合はエラー
https://wandbox.org/permlink/roGkNKKwsnaLX7og 
GCC の場合は OK
https://wandbox.org/permlink/AWd5A19WWDznccfq

エラーとなるのは gX 関数の PEEP で、オーバーロードされた関数があるとダメなようです。
Visual Studio はバージョンによって static メンバー関数がダメだったりするのは認識してましたが、 clang でもうまくいかないケースがあることがわかりました。

この挙動に関してなにか進展があったら、追記したいと思います。

では。


0 件のコメント:

コメントを投稿