创建对象时,什么是空模板参数<>?

问题描述 投票:0回答:3

这是一些有效的语法:

std::uniform_real_distribution<> randomizer(0, 100);

它是如何工作的,它会自动推导出对象模板吗?为什么类型末尾需要写

<>
?我可以不去掉
<>
就一样吗?

c++ templates c++11
3个回答
27
投票

通常,当第一个参数和后续参数或唯一参数具有默认模板参数(如果是整数,则为类型或值)时,可以使用此方法并起作用。另一种情况是存在模板参数包但它是空的。

仍然需要

<>
将其识别为模板类型。

在这种情况下,类型声明为;

template <class RealType = double> class uniform_real_distribution;

因此,模板类

RealType

 的默认 
uniform_real_distribution
double
。相当于
std::uniform_real_distribution<double>


参考

C++ WD n4527,§14.3/4(模板参数)

当使用模板参数包或默认的

template-argument 时,template-argument 列表可以为空。在这种情况下,空的 <>

 括号仍应用作 
template-argument-list。 [ 示例:

template<class T = char> class String; String<>* p; // OK: String<char> String* q; // syntax error template<class ... Elements> class Tuple; Tuple<>* t; // OK: Elements is empty Tuple* u; // syntax error
  
  

-结束示例]


9
投票
该类有以下声明

template<class RealType = double> class uniform_real_distribution;

如您所见,它具有类型为

double

 的默认模板参数

所以这个声明

std::uniform_real_distribution<> randomizer(0, 100);

相当于

std::uniform_real_distribution<double> randomizer(0, 100);
    

0
投票
函数模板

为了实例化函数模板,模板参数必须已知,但不需要指定。这意味着如果您不指定模板参数,编译器会尝试从函数参数的值和类型中推断出它们。即使

<>

也是
没有必要

来自

C++WD n3797 § 14.8.2(模板参数推导)

当引用函数模板特化时,所有 模板参数应该有值。这些值可以明确地 指定,或在某些情况下,从使用中推断或从 默认模板参数。

所以这个编译得很好。

template <typename T> T add(const T &t1, const T &t2) { return t1 + t2; } int x = add(1, 7); double y = add(1.5, 2.3);

模板参数推导尝试确定模板参数 (类型模板参数Ti的类型,模板模板的模板 模板参数 TTi 和非类型模板参数的值 ii),可以将其代入每个参数P以产生 类型推导 A,与参数 A 的类型相同,之后 下面列出了调整。

如果有多个参数,则分别推导每个P/A对 然后将推导的模板参数组合起来。如果扣除 对于任何 P/A 对失败或不明确,或者不同对产生 不同的推导模板参数,或者如果有任何模板参数 既没有推论也没有明确指定,编译失败。

但是在

某些上下文中编译器无法推导出模板参数。例如,这两个实例都无法编译。

template <typename T> T add(const T &t1, const T &t2) { return t1 + t2; } double x = add(3.141, 10); template<std::size_t N> void f(std::array<int, 2 * N> a); std::array<int, 10> a; f(a); // note: f(std::array<int, N> a) would be able to deduce N
类模板

C++17 引入了

类模板参数推导(CTAD),它使编译器也可以从类实例化的初始化值中推导模板参数。与函数模板类似,即使没有 <>

,编译器也会尝试推断模板参数。
在 C++17 中编译没有任何错误。

array x{1, 2, 3}; std::pair p(2, 4.5); // deduces to std::pair<int, double> p(2, 4.5); std::tuple t(4, 3, 2.5); // same as auto t = std::make_tuple(4, 3, 2.5); std::less l; // same as std::less<void> l; template<class T> struct A { A(T, T); }; auto y = new A{1, 2}; // allocated type is A<int>
您还可以在定义中提供模板推导指南,以帮助编译器推导某些特定情况的类型。
例如,C++17 编译器拒绝编译它,即使类型很明显。

template <typename T, typename U> struct Pair { T first; U second; }; Pair<int, int> p1{1, 2}; // This is fine. Pair p2{1, 2}; // This gives error in C++17 // Although from C++20 onwards this also compiles.
聚合的类模板参数推导通常需要用户定义的推导指南,直到 C++20。

template <typename T, typename U> struct Pair { T first{}; U second{}; }; // A deduction guide for our Pair (needed in C++17 only) // Pair objects initialized with arguments of type T and U should deduce to Pair<T, U> template <typename T, typename U> Pair(T, U) -> Pair<T, U>; Pair<int, int> p1{ 1, 2 }; Pair p2{ 1, 2 };
仅当不存在模板参数列表时才执行类模板参数推导。如果指定了模板参数列表,则不会发生推导。这意味着它无法编译。

std::tuple<> t3(1, 2, 3); // Error: no matching constructor in tuple<>. // No deduction performed. std::tuple<int> t4(1, 2, 3); // Also error. All types not specified.
在您的情况下,

std::uniform_real_distribution

定义指定了默认模板参数。

template< class RealType = double > class uniform_real_distribution;
默认的 

double

 类型允许编译:
std::uniform_real_distribution<> randomizer(0, 100);

    

© www.soinside.com 2019 - 2024. All rights reserved.