C ++ 11 - шаблоны, друзья, decltype и модификаторы доступа - PullRequest
2 голосов
/ 05 ноября 2011

Что случилось, ребята,

Я пытаюсь перегрузить оператор сложения для моего математического векторного класса. Мой (на первый взгляд логически правильный) упрощенный код:

template<typename T>
class Vector2
{
private:
    T       m_data[2];

    template<typename U>
    friend auto operator+(Vector2<T> a, Vector2<U> b) -> Vector2<decltype(a.m_data[0] + b.m_data[0])>
    {
        Vector2<decltype(a.m_data[0] + b.m_data[0])> ret(   a.m_data[0] + b.m_data[0],
                                                            a.m_data[1] + b.m_data[1]   );

        return ret;
    }

public:
    inline Vector2(T x, T y)
    {
        m_data[0] = x;
        m_data[1] = y;
    }
};

int main()
{
    Vector2<float>  v1(0.5f, 0.5f);
    Vector2<float>  v2(1, 2);

    v2 + v1; // Line 29

    return 0;
}

Однако, GCC 4.6.1 дал мне это:

W:\projects\Awesome\BetterStuff\main.cpp||In function 'Vector2<decltype ((a.m_data[0] + b.m_data[0]))> operator+(Vector2<T>, Vector2<U>) [with U = float; T = float; decltype ((a.m_data[0] + b.m_data[0])) = float]':|
W:\projects\Awesome\BetterStuff\main.cpp|5|error: 'float Vector2<float>::m_data [2]' is private|
W:\projects\Awesome\BetterStuff\main.cpp|29|error: within this context|
||=== Build finished: 2 errors, 0 warnings (0 minutes, 0 seconds) ===|

И если бы я изменил второй вектор на вектор int, это дало бы мне больше (похожих) ошибок.

Самое близкое, к чему я пришел, это найти эту интересную страницу: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48884

Но, к сожалению, я не смог использовать это для решения своей проблемы. Я пробовал GCC 4.6.2 и 4.7.0, но мой код тоже не компилировался.

Изменение «private» на «public» действительно решает мою проблему, но, очевидно, я не намерен выставлять m_data;

Я просто хочу определить оператор сложения, чтобы его тип возвращаемого значения определялся параметрами шаблона, что, как я понимаю, является временем компиляции - для каждого экземпляра функции шаблона компилятор автоматически вычисляет тип возвращаемого значения на основе на decltype () есть. Я имею в виду, каким образом main () пытается получить доступ к содержимому m_data для одного из этих векторов?

Все это смущает меня, любая помощь будет принята с благодарностью.

ОК, спасибо

Ответы [ 4 ]

4 голосов
/ 07 ноября 2011

Ну, GCC прав ... Проблема была не в том, что Vector2 (float) пытался получить доступ к закрытым членам Vector (int), а в том, что operator + (который только друг Vector2(float)) пытался получить доступ к закрытым членам Vector2 (int).Итак, обновленный код:

template<typename T>
class Vector2
{
    template<typename U>
    friend class Vector2;

private:
    T       m_data[2];

    template<typename T1, typename U>
    friend auto operator+(Vector2<T1> a, Vector2<U> b) -> Vector2<decltype(a.m_data[0] + b.m_data[0])>;

public:
    inline Vector2(T x, T y)
    {
        m_data[0] = x;
        m_data[1] = y;
    }

    inline Vector2<T>& operator=(const Vector2<T>& vec)
    {
        m_data[0] = vec.m_data[0];
        m_data[1] = vec.m_data[1];
    }
};

template<typename T, typename U>
auto operator+(Vector2<T> a, Vector2<U> b) -> Vector2<decltype(a.m_data[0] + b.m_data[0])>
{
    Vector2<decltype(T() + U())> ret(   a.m_data[0] + b.m_data[0],
                                        a.m_data[1] + b.m_data[1]   );

    return ret;
}

int main()
{
    Vector2<float>  v1(0.5f, 0.5f);
    Vector2<int>    v2(1, 2);

    //Vector2<int>  a = v2 + v1; // Doesn't work
    Vector2<float>  b = v2 + v1; // Works

    return 0;
}
1 голос
/ 05 ноября 2011

Проще говоря: вы не можете получить доступ к закрытым членам другого класса. Vector2<float> и Vector2<int> являются различными классами. Вы можете исправить это, добавив это в свой класс

template<typename T> friend class Vector2;

Которые будут дружить со всеми типами Vector2. Тогда вы можете получить доступ к рядовым Vector2.

1 голос
/ 05 ноября 2011

Проблема в том, что Vector2<T> и Vector2<U> - это разные совершенно не связанные классы, если T! = U.То, что вы пытаетесь сделать, - это то же самое, что иметь class A доступ к закрытым членам несвязанных class B.

. Предоставить надлежащие средства доступа для вашего Vector2 (возможно, оператор индекса) и реализовать ваш operator s использует такие открытые интерфейсы.

0 голосов
/ 05 ноября 2011

Не используйте приватный член в decltype, как отмечено выше.Кроме того, я сделал публичным оператор сложения.Я не думаю, что это неразумно.Я также добавил аксессуары coodinate.Это работает:

template<typename T>
class Vector2
{
private:
    T       m_data[2];
public:
    template<typename U>
    friend auto operator+(Vector2<T> a, Vector2<U> b) -> Vector2<decltype(T() + U())>
    {
        Vector2<decltype(T() + U())> ret( a[0] + b[0],
                                          a[1] + b[1] );

        return ret;
    }
    inline Vector2(T x, T y)
    {
        m_data[0] = x;
        m_data[1] = y;
    }
    inline T operator[](int c) const { return m_data[c]; }
};

int main()
{
    Vector2<float>  v1(0.5f, 0.5f);
    Vector2<int>  v2(1, 2);

    v2 + v1; // Line 29

    return 0;
}

при условии, что T и U имеют ctors по умолчанию.

...