带有模板类默认参数的C++ 17别名模板

Mar*_*ark 10 c++ alias templates class c++17

似乎C++ 17在所有参数都有默认值时添加了在模板类上删除"<>"的能力(就像我们已经能够长时间使用函数一样),例如:

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;
}
Run Code Online (Sandbox Code Playgroud)

但是,使用别名模板时,似乎该功能不再有效,例如:

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;
}
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎是出乎意料的行为.是否有任何变通方法仍然允许"<>"被删除?(我知道可以使用不同的名称创建单独的typedef,例如:使用MyAlias2 = MyStruct <>,但我想要相同的名称.我也知道定义可以欺骗它,例如#define MyAlias MyStruct,但是假设只是万不得已.)

Bar*_*rry 7

这对我来说似乎是出乎意料的行为.是否有任何变通方法仍然允许"<>"被删除?

这是预期的行为.好吧,取决于你的预期我猜.类模板参数推导适用于使用主类模板名称而不指定任何模板参数的上下文,并且仅适用于创建对象的上下文中.

它不适用于别名模板的上下文(如OP中所示).它不适用于函数模板推导的上下文.

除非有人建议改变这个,否则解决方法就是写MyAlias<>.


有一个提议来概括using声明,因此假设您可以编写using MyAlias = MyStruct;并将其作为别名模板.在这种情况下,它似乎合理的允许MyAlias c;,因为MyAlias直接名称的类模板.

但是一般问题更复杂,因为别名模板可以执行重新排序类型或添加新类型之类的操作.你必须回答以下问题:

template <typename T> using tuple_int = std::tuple<T, int>;
tuple_int t(4, 2);   // would this work? how?
tuple_int u(4, '2'); // what about this?
Run Code Online (Sandbox Code Playgroud)

我不是说没有答案.我只是说这不是一件小事.


Jod*_*cus 3

是否有任何解决方法仍然允许删除“<>”?

一种可能的解决方法是透明继承:

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;
}
Run Code Online (Sandbox Code Playgroud)

然而,一个(可能)危险的副作用是基类没有虚拟析构函数,如果多态使用,可能会导致内存泄漏。

这对我来说似乎是出乎意料的行为。

类模板参数推导(它启用您尝试使用的功能)似乎需要真实类模板的名称,而不是模板别名的名称。编译器基本上所做的就是转换

MyStruct obj;
Run Code Online (Sandbox Code Playgroud)

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

auto obj = f();
Run Code Online (Sandbox Code Playgroud)

但是,对于别名,您可以执行以下操作:

template <int LENGTH = 1>
using MyAlias = MyStruct<LENGTH + 1>;
Run Code Online (Sandbox Code Playgroud)

MyAlias如果上面的转换只是将名称替换为,那么它完全会错过“+ 1” MyStruct,这意味着这个问题没有简单的解决方案 - 但此时标准中没有任何地方处理这种情况,因此可以理解它不会编译。