C++11 Feature Proposal: Type aliases (using type = source_type)

540 views
Skip to first unread message

Alex Vakulenko

unread,
Sep 24, 2014, 4:20:30 PM9/24/14
to chromium-dev
What:

Use type aliases instead of typedef.

Example:

using MyStringMap = std::map<std::string, std::string>;

Instead of:

typedef std::map<std::string, std::string> MyStringMap;

Why:
using alias = type; is easier to read and understand, especially if you use it for function pointers:

using MyFncPtr = void (*)(int, string);

vs

typedef void (*MyFncPtr)(int, string);

Another (lesser) use case is that type aliases could be templates too, you can do this:

template<typename T>
using StringMapT = std::map<std::string, T>;

StringMapT<int> string_to_int_map;
StringMapT<double> string_to_double_map;

Where:
Pretty much everywhere typedefs are used...

James Robinson

unread,
Sep 24, 2014, 4:42:22 PM9/24/14
to Alex Vakulenko, chromium-dev
Sounds good to me.  One question is what to do with existing typedefs - I'd say leave them alone unless the type is being modified anyway, then switch to using.

http://msdn.microsoft.com/en-us/library/dn467695.aspx implies this works in Visual Studio 2013 and https://wiki.apache.org/stdcxx/C++0xCompilerSupport says this works as of GCC 4.7 and Clang 3.0, so we should be good there.


- James

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev

To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.

Peter Kasting

unread,
Sep 24, 2014, 6:18:20 PM9/24/14
to James Robinson, Alex Vakulenko, chromium-dev
On Wed, Sep 24, 2014 at 1:41 PM, James Robinson <jam...@chromium.org> wrote:
Sounds good to me.  One question is what to do with existing typedefs - I'd say leave them alone unless the type is being modified anyway, then switch to using.

Should we suggest that no new code use "typedef", then?  And if that's the case, maybe we actually should rewrite these?  Note that in the non-function-pointer case, the new syntax is the same number of characters overall.

PK 

Alex Vakulenko

unread,
Sep 24, 2014, 6:24:03 PM9/24/14
to Peter Kasting, James Robinson, chromium-dev
Should we suggest that no new code use "typedef", then?  And if that's the case, maybe we actually should rewrite these?  Note that in the non-function-pointer case, the new syntax is the same number of characters overall.

That's what I would recommend too. And being the same number of characters doesn't mean that it's as easy/difficult to read as typedef (unless you mean this as a positive thing, in fact that automatic rewrites would not change formatting too much and overflow 80 chars - which is true for simple typdefs that already fit on one line).

James Robinson

unread,
Sep 24, 2014, 6:25:14 PM9/24/14
to Peter Kasting, Alex Vakulenko, chromium-dev
Yeah, I can't think of any reason to say "typedef" once we support "using".

- James

 

PK 

Peter Kasting

unread,
Sep 24, 2014, 6:28:15 PM9/24/14
to Alex Vakulenko, James Robinson, chromium-dev
On Wed, Sep 24, 2014 at 3:23 PM, Alex Vakulenko <avaku...@chromium.org> wrote:
Should we suggest that no new code use "typedef", then?  And if that's the case, maybe we actually should rewrite these?  Note that in the non-function-pointer case, the new syntax is the same number of characters overall.

That's what I would recommend too. And being the same number of characters doesn't mean that it's as easy/difficult to read as typedef (unless you mean this as a positive thing, in fact that automatic rewrites would not change formatting too much and overflow 80 chars - which is true for simple typdefs that already fit on one line).

I meant it as a positive for the feasibility of rewriting.

PK

Alex Vakulenko

unread,
Sep 25, 2014, 3:25:32 PM9/25/14
to Peter Kasting, James Robinson, chromium-dev
So, why is this not on the list of allowed features yet?

Nico Weber

unread,
Sep 25, 2014, 3:30:20 PM9/25/14
to Alex Vakulenko, Peter Kasting, James Robinson, chromium-dev
'cause I don't want to add too much at once, and it seemed less useful than auto and for-range loops to me.

Alex Vakulenko

unread,
Sep 25, 2014, 4:05:21 PM9/25/14
to Nico Weber, Peter Kasting, James Robinson, chromium-dev
Fair enough

David Benjamin

unread,
Oct 9, 2014, 2:20:16 PM10/9/14
to avaku...@chromium.org, Nico Weber, Peter Kasting, James Robinson, chromium-dev
Is this worth adding now? This'll be useful in aligning the various platforms' base/containers/hash_tables.h on C++11 behavior. (Our current setup makes MSVC behave very differently from our other platforms.) For my CL, it looks subclassing may also work, but if we've already decided to allow these, it seems tidier.

https://codereview.chromium.org/623383002/

To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.

Viet-Trung Luu

unread,
Oct 9, 2014, 3:28:29 PM10/9/14
to davi...@chromium.org, Alex Vakulenko, Nico Weber, Peter Kasting, James Robinson, chromium-dev
I think we should do it.

On the other hand, I don't think it's worth the churn to convert (and then ban?) existing typedefs.

In particular, there are a few headers that have to be usable as C (e.g., ppapi/c, mojo/public/c), where we have to continue using typedef.

The real benefit is alias templates, which is what this CL needs.

Dana Jansens

unread,
Oct 9, 2014, 4:14:06 PM10/9/14
to Viet-Trung Luu, davi...@chromium.org, Alex Vakulenko, Nico Weber, Peter Kasting, James Robinson, chromium-dev
On Thu, Oct 9, 2014 at 3:27 PM, Viet-Trung Luu <viettr...@chromium.org> wrote:
I think we should do it.

+1 to adding this to the allowed list now, we've had a couple weeks now since we started allowing stuff.

James Robinson

unread,
Oct 9, 2014, 4:15:18 PM10/9/14
to Dana Jansens, Viet-Trung Luu, David Benjamin, Alex Vakulenko, Nico Weber, Peter Kasting, chromium-dev
Someone send me a patch to styeguide/c++/ and I'll approve it.

David Benjamin

unread,
Oct 9, 2014, 8:32:04 PM10/9/14
to James Robinson, Dana Jansens, Viet-Trung Luu, Alex Vakulenko, Nico Weber, Peter Kasting, chromium-dev

This is now on chromium-cpp.appspot.com.

Nico Weber

unread,
Oct 13, 2014, 12:47:19 PM10/13/14
to David Benjamin, James Robinson, Dana Jansens, Viet-Trung Luu, Alex Vakulenko, Peter Kasting, chromium-dev
Cool!

Do we really want to prefer this over typedef generally though? typedef has been around since K&R C, is widely used and understood, and is not particularly confusing unless you try really hard (e.g. `int typedef unsigned a;` is valid code, but nobody does that). But maybe I'm just having a hard time keeping up with progress :-)

On Thu, Oct 9, 2014 at 5:31 PM, David Benjamin <davi...@chromium.org> wrote:

This is now on chromium-cpp.appspot.com.


Antoine Labour

unread,
Oct 13, 2014, 3:45:55 PM10/13/14
to Nico Weber, David Benjamin, James Robinson, Dana Jansens, Viet-Trung Luu, Alex Vakulenko, Peter Kasting, chromium-dev
On Mon, Oct 13, 2014 at 9:46 AM, Nico Weber <tha...@chromium.org> wrote:
Cool!

Do we really want to prefer this over typedef generally though? typedef has been around since K&R C, is widely used and understood, and is not particularly confusing unless you try really hard (e.g. `int typedef unsigned a;` is valid code, but nobody does that). But maybe I'm just having a hard time keeping up with progress :-)

I personally prefer typedefs because the declaration order is consistent whether you're declaring a variable or a type (type goes first, identifier goes last). It feels easier to read because my brain doesn't need to switch from LTR to RTL parsing.

Antoine
 

On Thu, Oct 9, 2014 at 5:31 PM, David Benjamin <davi...@chromium.org> wrote:

This is now on chromium-cpp.appspot.com.


David Benjamin

unread,
Oct 13, 2014, 3:49:38 PM10/13/14
to Antoine Labour, Nico Weber, James Robinson, Dana Jansens, Viet-Trung Luu, Alex Vakulenko, Peter Kasting, chromium-dev
(I don't have particular opinions either way. Went with what people were saying on the thread at the time.)

Chris Hopman

unread,
Oct 13, 2014, 3:52:36 PM10/13/14
to pi...@google.com, Nico Weber, David Benjamin, James Robinson, Dana Jansens, Viet-Trung Luu, Alex Vakulenko, Peter Kasting, chromium-dev
A type alias or a typedef are more like a definition than they are like a declaration. For definitions it typically goes something like <type/keyword> <id> <value>.

Examples:

int a = 1;
class Foo {...};
Foo::Foo() {...};
Foo foo(val);
#define LOG(...) ...
using int_type = int;

Antoine Labour

unread,
Oct 13, 2014, 4:06:14 PM10/13/14
to Chris Hopman, Nico Weber, David Benjamin, James Robinson, Dana Jansens, Viet-Trung Luu, Alex Vakulenko, Peter Kasting, chromium-dev
On Mon, Oct 13, 2014 at 12:52 PM, Chris Hopman <cjho...@chromium.org> wrote:
A type alias or a typedef are more like a definition than they are like a declaration. For definitions it typically goes something like <type/keyword> <id> <value>.

Examples:

int a = 1;
class Foo {...};
Foo::Foo() {...};
Foo foo(val);
#define LOG(...) ...
using int_type = int;

I'll argue that several of these examples actually follow a pattern "type_of_thing thing" which is common in C/C++. E.g. you don't write a = int (1); or Foo = class {...}; or Foo::Foo = function() {...}; or LOG = define(...) ...

Antoine

Chris Hopman

unread,
Oct 13, 2014, 4:07:43 PM10/13/14
to Antoine Labour, Nico Weber, David Benjamin, James Robinson, Dana Jansens, Viet-Trung Luu, Alex Vakulenko, Peter Kasting, chromium-dev
Yeah, and for a type alias, the "type_of_thing" is from the keyword "using", i.e. it is an alias with the value of whatever type.

Viet-Trung Luu

unread,
Oct 13, 2014, 4:14:41 PM10/13/14
to David Benjamin, Antoine Labour, Nico Weber, James Robinson, Dana Jansens, Alex Vakulenko, Peter Kasting, chromium-dev
We could, of course, simply not be prescriptive and allow either (with the usual guidance to be locally consistent).

(This obviously favors the status quo, i.e., typedefs, but allows owners who feel strongly to go ahead with mass conversions of their directories.)

Vasily Chekalkin

unread,
Oct 13, 2014, 4:42:24 PM10/13/14
to pi...@google.com, Chris Hopman, Nico Weber, David Benjamin, James Robinson, Dana Jansens, Viet-Trung Luu, Alex Vakulenko, Peter Kasting, chromium-dev
+ piman@

 
 
14.10.2014, 07:05, "'Antoine Labour' via Chromium-dev" <chromi...@chromium.org>:


On Mon, Oct 13, 2014 at 12:52 PM, Chris Hopman <cjho...@chromium.org> wrote:
A type alias or a typedef are more like a definition than they are like a declaration. For definitions it typically goes something like <type/keyword> <id> <value>.
 
Examples:
 
int a = 1;
class Foo {...};
Foo::Foo() {...};
Foo foo(val);
#define LOG(...) ...
using int_type = int;
 
I'll argue that several of these examples actually follow a pattern "type_of_thing thing" which is common in C/C++. E.g. you don't write a = int (1); or Foo = class {...}; or Foo::Foo = function() {...}; or LOG = define(...) ...
 
It's common in c++11 actually.
 
auto f = new Foo;
auto foo() -> int { ... }
 
etc, etc
 
-- 
Bacek
 

Antoine Labour

unread,
Oct 13, 2014, 5:23:58 PM10/13/14
to Vasily Chekalkin, Chris Hopman, Nico Weber, David Benjamin, James Robinson, Dana Jansens, Viet-Trung Luu, Alex Vakulenko, Peter Kasting, chromium-dev
These uses of auto are disallowed or discouraged in Chromium code.

Antoine
 
 
etc, etc
 
-- 
Bacek
 

Sven Panne

unread,
Oct 14, 2014, 4:02:47 AM10/14/14
to avaku...@chromium.org, chromium-dev
On Wed, Sep 24, 2014 at 10:19 PM, Alex Vakulenko <avaku...@chromium.org> wrote:
[...] Another (lesser) use case is that type aliases could be templates too, you can do this:

template<typename T>
using StringMapT = std::map<std::string, T>;
[...]

Hmmm, I think this is not a "lesser use case", this was *the* motivation for introducing type aliases, at least that's how I understand it. One can program around this without "using", but that's less readable, so I think we should allow it for such cases.

All other use cases are just bikeshedding regarding the order of things, and what is "more natural" depends on the code around it, personal preferences, knowledge of other programming languages, etc. Personally I like the "using" syntax even for non-template stuff because it unifies types and values a bit (i.e. type alias syntax and assignment), but that's not really relevant.

Nico Weber

unread,
Oct 26, 2014, 6:00:04 PM10/26/14
to sven...@chromium.org, Alex Vakulenko, chromium-dev
Sounds like nobody except me cares too much either way, so let's keep this as is (i.e. let the style guide recommend using over typedef).

JAYTHACEO

unread,
Oct 28, 2014, 12:13:25 AM10/28/14
to chromi...@chromium.org
I agree. So when we encounter the old typedef replace with new one ?

Nico Weber

unread,
Oct 28, 2014, 12:14:37 AM10/28/14
to jayt...@gmail.com, Chromium-dev
I wouldn't rewrite existing code, I'd just use it for new code.

--

Nico Weber

unread,
Feb 18, 2015, 8:33:38 PM2/18/15
to JAYTHACEO, Chromium-dev
majn...@chromium.org tells me that this feature is somewhat broken in MSVS. This prints 1, while it should print 0:

#include <stdio.h>

template <typename>
struct A {};
template <typename T>
using AliasA = A<T>;

template <typename>
struct B {};
template <typename T>
using AliasB = B<T>;

template <template <typename> class>
void f() {}

int main() {
  printf("%d\n", &f<AliasA> == &f<AliasB>);
}


We do use template template parameters in a few (but not many) places (blink's wtf, v8, angle, gmock https://code.google.com/p/chromium/codesearch#search/&q=%5Cbtemplate%5Cb.*%5C%3C.*%5Cbtemplate%5Cb%20pcre:yes%20case:yes%20-file:usr/include%20file:%5C.(cc%7Ccpp%7Ch)$&sq=package:chromium&type=cs ), so it's conceivable that this might actually bite us if we try hard enough.

But so far, things seem to be ok in practice. So I think we can leave this in the "allowed" state – but if you're debugging something strange involving template template parameters and a templated using declaration and come across this thread, you're now aware of the above issue.

Alex Vakulenko

unread,
Feb 18, 2015, 9:44:53 PM2/18/15
to Nico Weber, JAYTHACEO, Chromium-dev
Well, there is definitely a bug here but I wouldn't call the "feature" is broken. The problem is how VS produces mangled function names when using template types in decoration. Apparently, for template functions, it uses the base types names in decorated names ignoring the template parameters.

So, for example:

template<typename T> struct A {};

template<template<typename> class>
void foo();

Referencing foo<A>() literally produces a function void foo<struct A>() and there is no trace of A being a template type. This is generally OK since you can't have both template and non-template version of struct A in the same scope. I guess when having type aliases they do not resolve the alias when generating the function name and since the alias doesn't have "a type name" in itself, it ends up being empty and produces something like void foo<>(). And in your example, both f<AliasA> and f<AliasB> become one function which is different from both f<A> and f<B>.

And that only affects the pure function name generation based on template parameters. If the function itself has parameters which also participate in name mangling, everything works as expected.

Here is a test I've done:

template<typename Tstruct A {};
template<typename Tusing AliasA = A<T>;
 
template<typename Tstruct B {};
template<typename Tusing AliasB = B<T>;
 
template<template<typenameclass Ctypename T>
void f(const C<T>&) {}
 
int main() {
  auto p1 = &f<AliasAint>;
  auto p2 = &f<AliasBint>;
  auto p3 = &f<Aint>;
  auto p4 = &f<Bint>;
  f(AliasA<int>{});
  f(AliasB<int>{});
  f(A<int>{});
  f(B<int>{});
}

After compiling this, here is the 32 bit assembly code produced. The funny part is that the compiler couldn't actually demangle the f<AliasA, int> and f<AliasB, int> when generating a comment. But you can see that calling the functions with a parameter actually resolves the type alias properly and uses the aliased type names ("A" and "B") instead.

; auto p1 = &f<AliasA, int>;
  mov    DWORD PTR _p1$[ebp], OFFSET ??$f@$H@@YAXABU?$A@H@@@Z ; ??$f@$H@@YAXABU?$A@H@@@Z
; auto p2 = &f<AliasB, int>;
  mov    DWORD PTR _p2$[ebp], OFFSET ??$f@$H@@YAXABU?$A@H@@@Z ; ??$f@$H@@YAXABU?$A@H@@@Z
; auto p3 = &f<A, int>;
  mov    DWORD PTR _p3$[ebp], OFFSET ??$f@UA@@H@@YAXABU?$A@H@@@Z ; f<A,int>
; auto p4 = &f<B, int>;
  mov    DWORD PTR _p4$[ebp], OFFSET ??$f@UB@@H@@YAXABU?$B@H@@@Z ; f<B,int>
; f(AliasA<int>{});
  xor    eax, eax
  mov    BYTE PTR $T1[ebp], al
  lea    ecx, DWORD PTR $T1[ebp]
  push   ecx
  call   ??$f@UA@@H@@YAXABU?$A@H@@@Z                ; f<A,int>
  add    esp, 4
 
; f(AliasB<int>{});
  xor    eax, eax
  mov    BYTE PTR $T2[ebp], al
  lea    ecx, DWORD PTR $T2[ebp]
  push   ecx
  call   ??$f@UB@@H@@YAXABU?$B@H@@@Z                ; f<B,int>
  add    esp, 4
 
; f(A<int>{});
  xor    eax, eax
  mov    BYTE PTR $T3[ebp], al
  lea    ecx, DWORD PTR $T3[ebp]
  push   ecx
  call   ??$f@UA@@H@@YAXABU?$A@H@@@Z                ; f<A,int>
  add    esp, 4
 
; f(B<int>{});
  xor    eax, eax
  mov    BYTE PTR $T4[ebp], al
  lea    ecx, DWORD PTR $T4[ebp]
  push   ecx
  call   ??$f@UB@@H@@YAXABU?$B@H@@@Z                ; f<B,int>
  add    esp, 4

 

So, the bottom line is, if you use template template parameters with functions and rely on function name itself (no parameter overloading), then you are in trouble. In other cases, it seems to still work fine.

Alex
Reply all
Reply to author
Forward
0 new messages