C++17中模板参数自动推导的优势

76

C++17可能引入的模板参数中使用auto的优势是什么?

当我想实例化模板代码时,它是否只是auto的自然扩展?

auto v1 = constant<5>;      // v1 == 5, decltype(v1) is int
auto v2 = constant<true>;   // v2 == true, decltype(v2) is bool
auto v3 = constant<'a'>;    // v3 == 'a', decltype(v3) is char

除此之外,这个语言特性还能为我带来什么好处?


4
附加信息:使用auto声明非类型模板参数 - t.niese
18
偶尔我会看到类似这个问题这个问题或者这个问题在StackOverflow上被提出。template < auto >会让这些提问者满意。 - cpplearner
我认为主要的事情是 std::vector<auto> v{1,2,3,4,5};,而困难的事情则是将可调用类型作为模板参数(尤其是 lambda 表达式)。 - emsr
@emsr:不,那不是它的作用。auto应该放在定义上,而不是使用的地方。 - Nicol Bolas
@emsr 这是概念 TS 的一个单独特性,不属于 C++17。但 p0127 中使用的 auto 不会与其冲突。 - Jonathan Wakely
4个回答

98
"

2016年ISO C++会议在芬兰奥卢接受了template <auto>特性(P0127R1)。

auto关键字在模板参数中表示一个非类型参数,其类型在实例化点被推导。可以将其视为更方便的写法:

"
template <typename Type, Type value>

例如,
template <typename Type, Type value> constexpr Type constant = value;
constexpr auto const IntConstant42 = constant<int, 42>;

现在可以写成

template <auto value> constexpr auto constant = value;
constexpr auto const IntConstant42 = constant<42>;

现在你不需要再明确地拼写出类型了。P0127R1 还包括一些简单但很好的例子,其中使用具有可变参数模板的 template <auto> 非常方便,例如用于实现编译时列表常量值:

template <auto ... vs> struct HeterogenousValueList {};
using MyList1 = HeterogenousValueList<42, 'X', 13u>;

template <auto v0, decltype(v0) ... vs> struct HomogenousValueList {};
using MyList2 = HomogenousValueList<1, 2, 3>;

在 C++1z 之前,尽管 HomogenousValueList 可以简单地写成:
template <typename T, T ... vs> struct Cxx14HomogenousValueList {};
using MyList3 = Cxx14HomogenousValueList<int, 1, 2, 3>;

编写等效于 HeterogenousValueList 的代码将不可能没有使用其他模板来包装这些值,例如:
template <typename ... ValueTypes> struct Cxx14HeterogenousValueList {};
using MyList4 = Cxx14HeterogenousValueList<constant<int, 42>,
                                           constant<char, 'X'> >;

非类型模板参数不能是任何东西,因此像constant<3.0>这样的东西是行不通的。泛型代码就到此为止了。 - jondoe
@jondoe一种可能的解决方法是使用std::ratio来代替浮点数值,并在需要时将它们转换为实际的浮点数值。 - mceo
3
C++20允许使用浮点数模板参数。 - Davis Herring
1
在您的最后一个示例中,constant 是一个值,因此无法传递给 typename - Dr. Gut

14

实际上,mceo的(原始)答案中实数情况明确未被视为非类型模板参数。

template <auto ... vs> struct HeterogenousValueList {};
using MyList1 = HeterogenousValueList<42, 'X', 1.3f>;

请参考提案中给出的示例: 修改§14.3.2第2段:
template<auto n> struct B { /* ... */ };
B<5> b1;   // OK: template parameter type is int
B<'a'> b2; // OK: template parameter type is char
B<2.5> b3; // error: template parameter type cannot be double

我几天前也刚好遇到了同样的误解。


2
虽然这很好知道,并且已经得到了赞同,但我现在不明白它与问题有什么关系。没有人现在建议将实际值用作非类型模板参数。 - einpoklum
2
这是对mceo原始答案的回复,他给出了一个实际值作为模板参数的示例,但这是不允许的。在编辑后,这个方面现在已经包含在上面被接受的答案中,并且现在基本上是多余的。 - m-j-w
4
这与问题相关,因为“auto”的引入并没有像人们很容易得到的印象那样悄悄地引入了新的模板参数类型。 - m-j-w
3
FYI,在C++20中,浮点数值可以作为模板参数。请参见http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1714r1.html。 - jorgbrown

7

这里是另一个例子(最初由@Rakete1111提供作为未知类型的模板模板参数的答案):

在不知道其类型的情况下提取SIZE的值:

template<std::size_t SIZE>
class Foo {};

template <template<auto> class T, auto K>
auto extractSize(const T<K>&) {
    return K;
}

int main() {
    Foo<6> f1;
    Foo<13> f2;
    std::cout << extractSize(f1) << std::endl;
    std::cout << extractSize(f2) << std::endl;
}

关于 C++17,在这种情况下,auto 是否限制为非类型模板参数的类型集? - 303
请问您能否解释一下这是如何工作的? - Alex O
@AlexO 我们将 K 作为模板参数进行捕获。与 typename 模板相同,auto 模板表示“任何类型,编译器请推断”,内部模板参数的 auto 表示“任何值的类型”,这在此处有所帮助,因为内部模板参数是非类型的。 - Amir Kirsh

6

C++20似乎增加了另一种用法

...但事实并非如此 :-(

概念(Concepts)技术规范允许在函数参数中使用auto模板参数占位符,例如:

void printPair(const std::pair<auto, auto>& p) {
    std::cout << p.first << ", " << p.second << std::endl;
}

但在 C++20 规范中,这个被移除了。

这是一个不错的用法... 我希望它会在 C++26 中再次出现!

参见:'auto' 作为函数参数的模板参数占位符


是的,这简化了很多样板代码,我也想要。GCC 可以编译这个,Clang 拒绝了。 - 0xB00B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接