Какова разница между 'typedef' и 'using'?
Я знаю, что в C++11 мы можем использовать ключевое слово using
для написания псевдонимов типов, аналогично typedef
. Например:
typedef int MyInt;
Что, как я понимаю, эквивалентно:
using MyInt = int;
Эта новая синтаксическая конструкция появилась в рамках попытки создать способ для выражения "псевдонимов типов через шаблоны":
template< class T > using MyType = AnotherType< T, MyAllocatorType >;
Однако, в случае с первыми двумя примерами (без шаблонов) есть ли какие-то другие тонкие различия в стандарте? Например, typedef
создает псевдонимы "слабым" образом. Это значит, что он не создает новый тип, а только новое имя (преобразования между этими именами являются неявными).
Так ли это с using
или он генерирует новый тип? Есть ли какие-либо различия между ними?
5 ответ(ов)
Они эквивалентны, согласно стандарту (выделение мое) (7.1.3.2):
Идентификатор (typedef-name) также может быть введен с помощью объявления-алиаса. Идентификатор, следующий за ключевым словом using, становится именем типа (typedef-name), а необязательная последовательность спецификаторов атрибутов (attribute-specifier-seq), следующая за идентификатором, относится к этому имену типа. У него те же семантические свойства, как если бы он был введен с помощью спецификатора typedef. В частности, он не определяет новый тип и не должен появляться в type-id.
Они в основном одинаковы, за исключением следующих моментов:
Объявление псевдонима совместимо с шаблонами, в то время как типовая запись в стиле C не совместима.
Синтаксис using имеет преимущества при использовании в шаблонах. Если вам нужна абстракция типа, но вы также хотите оставить возможность указать параметр шаблона в будущем, вам следует написать что-то вроде следующего.
template <typename T> struct whatever {};
template <typename T> struct rebind
{
typedef whatever<T> type; // чтобы в будущем можно было заменить whatever.
};
rebind<int>::type variable;
template <typename U> struct bar { typename rebind<U>::type _var_member; }
Однако синтаксис using упрощает этот случай использования.
template <typename T> using my_type = whatever<T>;
my_type<int> variable;
template <typename U> struct baz { my_type<U> _var_member; }
Оба ключевых слова эквивалентны, но есть несколько нюансов. Во-первых, объявление указателя на функцию с помощью using T = int (*)(int, int);
более ясно, чем с использованием typedef int (*T)(int, int);
. Во-вторых, форма алиаса шаблона невозможна с typedef
. В-третьих, при экспортировании C API потребуется использовать typedef
в публичных заголовках.
using
и typedef
по сути выполняют одну и ту же функцию, но using
предоставляет возможность создавать alias templates
, что может быть весьма полезно. Пример, который хорошо иллюстрирует это, следующий:
namespace std {
template<typename T> using add_const_t = typename add_const<T>::type;
}
Таким образом, вместо того чтобы писать typename std::add_const<T>::type
, мы можем просто использовать std::add_const_t<T>
. Это делает код более читаемым и удобным.
Что такое лямбда-выражение и когда его следует использовать?
Почему следует использовать указатель вместо самого объекта?
push_back против emplace_back: в чем разница?
Что означает T&& (двойной амперсанд) в C++11?
В чем разница между constexpr и const?