2

次のコードについて考えてみます。

#include <cstddef>

template<size_t value> class dummy { };

class my_class
{
    int m_member;

    // Overload 1
    template<size_t value>
    friend void friend_func(dummy<value>*);

    // Overload 2
    template<size_t value>
    friend void friend_func(int(*)[value]);
};

// Overload 1
template<size_t value>
void friend_func(dummy<value>*)
{
    my_class instance;
    instance.m_member = value;
}

// Overload 2
template<size_t value>
void friend_func(int(*)[value])
{
    my_class instance;
    instance.m_member = value;
}

int main(int argc, char* argv[])
{
    dummy<5> d;
    friend_func(&d);    // call Overload 1
    int arr[5];
    friend_func(&arr);  // call Overload 2 - error in MSVC!
    return 0;
}

ご覧のとおり、これら2つの関数の唯一の違いは、2番目の関数が。value intではなくsへのポインターを受け取ることですdummy<value>。このコードは、GCC($ gcc-4.7.2 test.cpp)とClang(WhozCraigに感謝)では問題なくコンパイルされますが、MSVCでは次のエラーがスローされます(2012年にテストしました)。

1>d:\path\to.cpp(32): error C2248: 'my_class::m_member' : cannot access private member declared in class 'my_class'
1>          d:\path\to.cpp(8) : see declaration of 'my_class::m_member'
1>          d:\path\to.cpp(7) : see declaration of 'my_class'
1>          d:\path\to.cpp(40) : see reference to function template instantiation 'void friend_func<5>(int (*)[5])' being compiled

私にはこれはバグのように見えます。しかし、以前にそのような行動に遭遇した人はいますか?それは本当にバグですか、それともエラーの特定の理由がありますか?これに対する簡単な回避策はありますか?


編集:適切な回避策を見つけることができました。以下の回答を参照してください。

4

3 に答える 3

2

これは間違いなくバグです。配列のサイズでパラメーター化されたテンプレート関数は、クラスのフレンドとして宣言できませんvalueこれは、フレンドテンプレート関数の配列のサイズとしてが推定されるときに発生します。これは、正常にコンパイルされるコードの短縮バージョンです。この例は、配列のサイズを指定したことを除いて、例とまったく同じコードです。

class my_class
{
    int m_member;

    template<size_t value>
    friend void friend_func(int(*)[5]);
};

template<size_t value>
void friend_func(int(*)[5])
{
    my_class instance;
    instance.m_member = value;
}

int main()
{
    int arr[5];
    friend_func<5>(&arr);
}

value2番目の関数の引数としてを渡すための1つの回避策:

template <typename T>
void friend_func(T, int value)
{
    my_class instance;
    instance.m_member = value;
}
于 2013-03-01T04:10:21.540 に答える
0

機能を維持しながら、エラーメッセージを防止するという回避策を考え出しました。アイデアは、プロキシ関数とプロキシクラスを使用して、配列とそのサイズへのポインタを運ぶことです。解決策は次のとおりです。

#include <cstddef>

// Workaround class for a bug in MSVC.
// https://connect.microsoft.com/VisualStudio/feedback/details/717749
// http://stackoverflow.com/questions/15149607
template<class element_type, size_t count>
class friend_declaration_bug_workaround
{
public:
    typedef element_type(*ptr_type)[count];

private:
    ptr_type m_arr;

public:
    explicit friend_declaration_bug_workaround(ptr_type arr)
        : m_arr(arr)
    {
    }

    ptr_type value() const
    {
        return m_arr;
    }
};

class my_class
{
    int m_member;

    friend void friend_func(int*);

    template<size_t value>
    friend void friend_func_workaround(friend_declaration_bug_workaround<int, value>);
};

template<size_t value>
void friend_func_workaround(friend_declaration_bug_workaround<int, value> workaround)
{
    my_class instance;
    instance.m_member = (*workaround.value())[0];
}

void friend_func(int* arr)
{
    my_class instance;
    instance.m_member = *arr;
}

template<size_t value>
void friend_func(int(*arr)[value])
{
    friend_declaration_bug_workaround<int, value> workaround(arr);
    return friend_func_workaround(workaround);
}

int main(int argc, char* argv[])
{
    int value;
    friend_func(&value);    // call non-templated function
    int arr[5];
    friend_func(&arr);      // call workarounded function
    return 0;
}
于 2013-03-01T05:17:55.993 に答える
0

これはMSVSの既知の問題であることは間違いありません。特定の問題は、boost.orgの移植性のヒント:Micrsoft VisualC++にリストされています。

友達としてテンプレートを探します。回避策はわかりません。ただし、クラスを友達にすることはできると思います。これを回避策として使用できる場合があります。

于 2013-03-01T03:23:28.407 に答える