Difference Between 'Typedef' and 'Using' in C++11

What is the difference between 'typedef' and 'using' in C++11?

All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.



Typedef declarations can, whereas alias declarations cannot(+), be used as initialization statements

But, with the first two non-template examples, are
there any other subtle differences in the standard?

  • Differences in semantics: none.
  • Differences in allowed contexts: some(++).

(+) P2360R0 (Extend init-statement to allow alias-declaration) has been approved by CWG and as of C++23, this inconsistency between typedef declarations and alias declarations will have been removed.


(++) In addition to the examples of alias templates, which has already been mentioned in the original post.

Same semantics

As governed by [dcl.typedef]/2 [extract, emphasis mine]

[dcl.typedef]/2 A
typedef-name
can also be introduced by an
alias-declaration.
The identifier following the using keyword becomes a
typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. Such a
typedef-name has the same semantics as if it were introduced by the typedef specifier.
[...]

a typedef-name introduced by an alias-declaration has the same semantics as if it were introduced by the typedef declaration.

Subtle difference in allowed contexts

However, this does not imply that the two variations have the same restrictions with regard to the contexts in which they may be used. And indeed, albeit a corner case, a typedef declaration is an init-statement and may thus be used in contexts which allow initialization statements

// C++11 (C++03) (init. statement in for loop iteration statements).
for (typedef int Foo; Foo{} != 0;)
// ^^^^^^^^^^^^^^^ init-statement
{
}

// C++17 (if and switch initialization statements).
if (typedef int Foo; true)
// ^^^^^^^^^^^^^^^ init-statement
{
(void)Foo{};
}

switch (typedef int Foo; 0)
// ^^^^^^^^^^^^^^^ init-statement
{
case 0: (void)Foo{};
}

// C++20 (range-based for loop initialization statements).
std::vector<int> v{1, 2, 3};
for (typedef int Foo; Foo f : v)
// ^^^^^^^^^^^^^^^ init-statement
{
(void)f;
}

for (typedef struct { int x; int y;} P; auto [x, y] : {P{1, 1}, {1, 2}, {3, 5}})
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ init-statement
{
(void)x;
(void)y;
}

whereas an alias-declaration is not an init-statement, and thus may not be used in contexts which allows initialization statements

// C++ 11.
for (using Foo = int; Foo{} != 0;) {}
// ^^^^^^^^^^^^^^^ error: expected expression

// C++17 (initialization expressions in switch and if statements).
if (using Foo = int; true) { (void)Foo{}; }
// ^^^^^^^^^^^^^^^ error: expected expression

switch (using Foo = int; 0) { case 0: (void)Foo{}; }
// ^^^^^^^^^^^^^^^ error: expected expression

// C++20 (range-based for loop initialization statements).
std::vector<int> v{1, 2, 3};
for (using Foo = int; Foo f : v) { (void)f; }
// ^^^^^^^^^^^^^^^ error: expected expression

C++ 'typedef' vs. 'using ... = ...' [duplicate]

They are the same.

To quote the C++11 standard (or the draft to be specific):

A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword
becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that
typedef-name. It has the same semantics as if it were introduced by the typedef specifier. In particular, it
does not define a new type and it shall not appear in the type-id.

I think the "the same semantics as the typedef specifier" say it all.

Using typedef or using to define a structure - which is best?

Even better is to use neither. One type name should be enough. Pick either tagExportSettings or EXPORT_SETTINGS_S and stick with it. Example:

struct tagExportSettings
{
// ...
};

But, 1. All my code in the software uses EXPORT_SETTINGS_S

As I said, pick either name. If you use EXPORT_SETTINGS_S, then name the class as EXPORT_SETTINGS_S:

struct EXPORT_SETTINGS_S
{
// ...
};

If something still refers to tagExportSettings, then refactor the code to use the canonical name.


But more generally, using is preferred to typedef because it's more readable. There are at least two reasons for it:

  1. With typedef syntax it isn't intuitive which is the old name and which is the new alias:

    typedef new_or_old old_or_new; // old_or_new is the new alias

    using is intuitive through familiar pattern of initialisation:

    using intuitively_alias = intuitively_old_name;
  2. typedef syntax is difficult for a programmer to parse in case of compound names because the alias is "interleaved":

    // alias for void()
    typedef void function();
    using function = void();

Difference between typedef and C++11 type alias [duplicate]

There is absolutely no difference between both.

If you take a look at the standard :

7.1.3 The typedef specifier [dcl.typedef ]

A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name. It has the same semantics as if it were introduced by the typedef specifier. In particular, it does not define a new type and it shall not appear in the type-id.

7.3.3 The using declaration [namespace.udecl]

If a using-declaration uses the keyword typename and specifies a dependent name (14.6.2), the name introduced by the using-declaration is treated as a typedef-name.


However from this page : http://en.cppreference.com/w/cpp/language/type_alias

It is said :

Type aliases are similar to typedefs, however, have the advantage of working with templates.

It seems that this

// template type alias
template<class T> using ptr = T*;
// the name 'ptr<T>' is now an alias for pointer to T
ptr<int> x;

is only possible with the using directive.


And do not forget that this is a C++11 feature. Some compilers do not support it yet.

What's the difference between using-style and typedef-style? [duplicate]

The "using-style" was introduced to allow templated typedefs:

template< typename T >
using int_map = std::map< int, T >;

You can not do this with typedef. I found it strange myself that it was decided to use using and not typedef as the keyword for this, but I guess the committee must have found some problem with extending the typedef syntax.

C++11, using vs typedef, templatized

using Point = ...; is a type alias (formally called just 'alias'). I.e., it's just a different syntax for typedef where the type involved is named in ....

template<typename T> using Point = ...; is an alias template, where the type involved is again named in ....

What both aliases and alias templates have in common is that both must refer to a type-id (C++11 [basic.scope.pdecl]p3). Type-ids must in turn name types. (Go figure.)

The problem is that template<typename T> struct {T x, y;} is not a type, but a class template, and as just established alias templates must refer to types. As to changing your code to resolve your problem, I've no idea as you haven't said what it is... ;-] Regarding that, please see What is the XY problem?

Why do type aliases in C++ use 'using' instead of 'typedef' in their syntax?

What you suggest was actually proposed back in 2002 in document N1406 by Herb Sutter. It would allow, for example, to write:

template<typename T> typedef X<T,int> Xi; 

This was later revised in N1449 by Gabriel Dos Reis and Mat Marcus. They adopt the using syntax, and note the following:

Note that we specifically avoid the term “typedef template” and introduce the new syntax involving the pair “using” and “=” to help avoid confusion: we are not defining any types here, we are introducing a synonym (i.e. alias) for an abstraction of a type-id (i.e. type expression) involving template parameters.

They also state:

Two straw polls were taken regarding syntax. A strong majority voted to avoid the typedef template syntax, in favor of the “=” syntax. A second vote indicated strong preference for the “using” keyword as opposed to a word like “alias” or the absence of any keyword as in the draft version of this proposal. The motivation for using any keyword at all stemmed partly from the desire to use a syntax that might be compatible with the non-template aliasing direction briefly outlined above.

This syntax was then adopted in the final proposal N2258 by Gabriel Dos Reis and Bjarne Stroustrup.

What are the differences between typedef, using, namespace and using namespace in C++?

boost::filesystem is a namespace, not a type. So you can do this:

namespace FS = boost::filesystem;


Related Topics



Leave a reply



Submit