MSVC朋友函数声明bug

时间:2013-03-01 02:45:51

标签: c++ templates visual-c++

考虑以下代码:

#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;
}

正如您所看到的,这两个函数之间的唯一区别是第二个函数指向value int而不是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

对我而言,这看起来像一个错误。但是,有没有人之前遇到过这样的行为?它真的是一个错误,或者错误的特定原因是什么?有什么快速的解决方法吗?


修改:我已找到合适的解决方法,请参阅answer below

3 个答案:

答案 0 :(得分:2)

这绝对是一个错误:A template function parametrized on the size of an array cannot be declared as a friend of a class。当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);
}

一种解决方法是将value作为第二个函数参数传递:

template <typename T>
void friend_func(T, int value)
{
    my_class instance;
    instance.m_member = value;
}

答案 1 :(得分:0)

很确定这是MSVS的已知问题。您的具体问题列在Portability Hints: Micrsoft Visual C++ on boost.org

将模板视为朋友。我不知道这个工作。但是,我认为你可以把课程变成朋友。您可以将其用作解决方法。

答案 2 :(得分: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;
}