Существуют ли случаи, когда typedef абсолютно необходим?
Рассмотрим следующий отрывок из безопасного идиома bool:
typedef void (Testable::*bool_type)() const;
operator bool_type() const;
Можно ли объявить функцию преобразования без typedef? Не компилируется следующее:
operator (void (Testable::*)() const)() const;
Ответы
Ответ 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; }
};