Подтвердить что ты не робот

Существуют ли случаи, когда typedef абсолютно необходим?

Рассмотрим следующий отрывок из безопасного идиома bool:

typedef void (Testable::*bool_type)() const;
operator bool_type() const;

Можно ли объявить функцию преобразования без typedef? Не компилируется следующее:

operator (void (Testable::*)() const)() const;
4b9b3361

Ответ 1

А, я просто вспомнил мета-функцию identity. Можно написать

operator typename identity<void (Testable::*)() const>::type() const;

со следующим определением identity:

template <typename T>
struct identity
{
    typedef T type;
};

Можно утверждать, что identity по-прежнему использует typedef, но для меня это "хорошо".

Ответ 2

Один случай (не связанный с вашим вопросом), где требуется typedef, используется при использовании

va_arg() макрос. Цитирование стандарта C99 (7.15.1.1):

type * va_arg (va_list ap, type);

...

Тип параметра должен быть имя типа, указанное таким образом, что тип указателя на объект, который указанный тип может быть получен просто путем постфиксации a * на Тип

Ответ 3

Отвечая на вопрос "Существуют ли случаи, когда typedef абсолютно необходим?" из названия вопроса, вот один пример того, где требуется typedef:

f(unsigned char());   // compiler error!
typedef unsigned char Byte;
f(Byte());            // fine!

Смотрите результаты здесь: http://ideone.com/JPUra

Ответ 4

В моем анализе говорится, что это невозможно без использования typedef. Компилятор видит ( в качестве первого токена и предполагает, что вы перегружаете () operator, у которого не должно быть никаких аргументов (аргументы будут приведены в следующем наборе скобок). Помещение любого набора дополнительных круглых скобок не помогло бы - но на самом деле путало бы компилятор и, следовательно, увеличивало количество ошибок.

Большинство STL-кода находятся поверх typedef -исследований, и мы должны/должны их использовать!

Ответ 5

Кажется, что грамматика требует использования typedef в вашем случае. Идентификатор функции преобразования должен иметь вид operator. Идентификатор типа преобразования не может содержать круглые скобки. Таким образом, вы должны использовать typedef при преобразовании в тип указателя на функцию или в тип типа указателя на член.

Ответ 6

В С++ 11 вы можете сделать это так (gcc 4.5.2):

operator decltype((void (Testable::*)() const)(0))() const ;

Я не говорю это довольно...

Ответ 7

A typedef не является макросом, ваш второй пример не эквивалентен первому. В первом случае ваш typedef определяет функтор, а затем использует этот тип в литовом операторе типа функтора. Во втором оператор использует плохой синтаксис, поскольку оператор не указан, потому что нет типа. Я не уверен, как писать, но обычно есть способ.

Typedefs действительно не нужны, кроме как сделать код для чтения человеком в TMP, и даже тогда это зависит от того, кем вы являетесь.

Так как я не могу придумать альтернативный синтаксис, возможно, в некоторых случаях потребуются typedef. Я просто подумал о другом. Скажем, у вас был шаблон со специализациями, который содержал статический метод с возвращаемым типом, как показано ниже:

template <typename T>
struct WhateverHandler
{
   typedef T rType;
   static rType Whatever() { return rType(); }
};

template <>
struct WhateverHandler<std::string>
{
   typedef std::string rType;
   static rType Whatever() { return rType(); }
};

Я думаю, что в этом случае вам также понадобится typedef, чтобы вызвать статический метод независимо от специализации, поскольку в противном случае метод мог бы запутать компилятор, потому что типы возвращаемых данных будут отличаться, но это не будет надлежащей перегрузкой.

template <typename T>
struct WhateverUser
{
   typename WhateverHandler<T>::rType DoWhatever()
   {
       return WhateverHandler<T>::template Whatever();
   }
};

Ответ 8

Я просто столкнулся с этой проблемой, используя clang++:

foo.cpp:17:8: error: must use a typedef to declare a conversion to 'void (*(int))()'

и существует шаблон STL С++ 11, который покрывает идентификатор <T> Функциональность:

#include <type_traits>
…
struct foo {
     void bar( ) const { }
     operator std::common_type<void(foo::*)( )const>::type( ) { return &foo::bar; }
};