C++17 alias template with template class default arguments

  • A+
Category:Languages

It seems like C++17 added the ability to drop the "<>" on template classes when all the arguments have defaults (just like we've been able to do with functions for a long time) e.g.:

template<int LENGTH = 1> struct MyStruct{ int arr[LENGTH]; };  int main() {     MyStruct<2> a;     MyStruct<> b; // old way to use defaults     MyStruct c; // new way to use defaults     return 0; } 

However, it seems like that feature no longer works when using an alias template e.g.:

template<int LENGTH = 1> struct MyStruct{ int arr[LENGTH]; };  template<int LENGTH = 1> using MyAlias = MyStruct<LENGTH>;  int main() {     MyAlias<2> a;     MyAlias<> b; // old way still works     MyAlias c; // new way doesn't compile:     // gcc 7.3: missing template arguments before 'c'     // clang 6.0.0: declaration of variable 'c' with deduced type 'MyAlias' requires an initializer     return 0; } 

That seems like unexpected behavior to me. Are there any workarounds to still allow the "<>" to be dropped? (I know a separate typedef could be created with a different name, e.g.: using MyAlias2 = MyStruct<>, but I want the same exact name. I also know a define could trick it, e.g. #define MyAlias MyStruct, but assume that would only be a last resort.)


Are there any workarounds to still allow the "<>" to be dropped?

A possible workaround may be a transparent inheritance:

template<int LENGTH = 1> struct MyStruct{ int arr[LENGTH]; };  template<int LENGTH = 1> struct MyAlias : MyStruct<LENGTH> { };  int main() {     MyAlias<2> a;     MyAlias<> b;     MyAlias c;     return 0; } 

A (possibly) dangerous side-effect is however that the base class has no virtual destructors, leading to a possible memory leak if used polymorphically.

That seems like unexpected behavior to me.

Class template argument deduction, which enables the feature you are trying to use, appears to require a name of a real class template, not that of an template alias. What the compiler basically does is something like transforming

MyStruct obj; 

to

template <int LENGTH=1> MyStruct<LENGTH> f() { return MyStruct<Length>{ }; }  auto obj = f(); 

However, for aliases, you could do something like this:

template <int LENGTH = 1> using MyAlias = MyStruct<LENGTH + 1>; 

The above transformation totally would miss that "+ 1" if it just replaced the name MyAlias by MyStruct, implying there is no trivial solution to this problem - but by this time nowhere in the standard this case is handled, so its understandable it will not compile.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: