C ++ с использованием typedefs в не встроенных функциях - PullRequest
3 голосов
/ 14 мая 2010

У меня есть такой класс

template< typename T >
class vector {
  public:
    typedef T &       reference;
    typedef T const & const_reference;
    typedef size_t    size_type;

    const_reference at( size_t ) const;
    reference at( size_t );

и позже в том же файле

template< typename T >
typename vector<T>::const_reference    // Line X
vector<T>::at( size_type i ) const
{
    rangecheck();
    return elems_[ i ];
}


template< typename T >
reference                              // Line Y
vector<T>::at( size_type i )
{
    rangecheck();
    return elems_[ i ];
}

Строка X компилируется нормально, но строка Y не компилируется. Сообщение об ошибке от g ++ (версия 4.4.1):

foo.h:Y: error: expected initializer before 'vector'

Отсюда я понимаю, что, если я хочу иметь не встроенные функции, я должен полностью указать имя typedef, как в строке X. (Обратите внимание, что для size_type нет проблем).

Однако, по крайней мере для меня, Линия X выглядит неуклюжей.

Есть ли альтернативный подход?

Ответы [ 3 ]

4 голосов
/ 14 мая 2010

Да, в определении функции-члена вне класса вы должны использовать полное имя для вложенного возвращаемого типа. Это, кстати, не имеет ничего общего с шаблонами. Так же и с не шаблонными классами.

В вашем случае это шаблонный класс, и, как следствие этого, поскольку вы используете квалифицированное имя для ссылки на вложенный тип в зависимом шаблонном классе, вы должны добавить к нему ключевое слово typename.

Однако вам нужно только указать тип возвращаемого значения. Типы параметров не нужно указывать

template< typename T >
typename vector<T>::const_reference
  vector<T>::some_method( const_reference r ) const
{
  // ...
}

Вы можете также использовать квалифицированное имя для типа параметра, но в этом случае вам придется сделать то же самое, что и с типом возвращаемого значения (по той же причине): добавьте к нему ключевое слово typename

template< typename T >
typename vector<T>::const_reference
  vector<T>::some_method( typename vector<T>::const_reference r ) const
{
  // ...
}
3 голосов
/ 14 мая 2010

Из действующего C ++, пункт 42: «всякий раз, когда вы ссылаетесь на имя вложенного зависимого типа в шаблоне, вы должны немедленно предшествовать ему словом typename» size_t не является вложенным внутри чего-либо, зависящего от параметра шаблона. Вы сделали typedef, но это всегда будет size_t.

Вот как это будет выглядеть size_type DID зависит от параметра шаблона.

#include <cstddef>

template< typename T >
class vector {
  public:
    typedef T &       reference;
    typedef T const & const_reference;

    const_reference at( typename T::size_type ) const;
    reference at( typename T::size_type );
};

template< typename T >
typename vector<T>::const_reference
vector<T>::at( typename T::size_type i ) const
{
    // ...
}

template< typename T >
typename vector<T>::reference
vector<T>::at( typename T::size_type i )
{
    // ...
}

struct Foo
{
    typedef size_t size_type;
};

int main()
{
    vector<Foo> f;
    return 0;
}

size_type - это вложенный тип Foo.

2 голосов
/ 14 мая 2010

Вы правы; тип должен быть квалифицирован, потому что ваши typedef определены в области видимости класса, а не в глобальной области видимости. Я не знаю никакого способа украсить это, не загрязняя глобальный охват, что было бы плохой идеей. Но, похоже, ваши функции очень короткие, так почему бы вам просто не определить их встроенными? Это избавит вас от лишнего набора текста, и, ИМХО, его легче читать.

...