【问题标题】:Template default argument loses its reference type模板默认参数丢失其引用类型
【发布时间】:2020-01-09 05:23:22
【问题描述】:

考虑

#include <iostream>
#include <type_traits>

template <class T, class ARG_T = T&>
T foo(ARG_T v){
    return std::is_reference<decltype(v)>::value;
}

int main() {
    int a = 1;
    std::cout << foo<int>(a) << '\n';
    std::cout << foo<int, int&>(a) << '\n';
}

我希望这两种情况下的输出都是 1。但在第一种情况下,它是 0:与默认值为 class ARG_T = T 而不是 class ARG_T = T&amp; 一致。

我错过了什么?

【问题讨论】:

  • 好的,为了清楚起见(在有些复杂的答案之后):您的问题与 default 参数 无关,因为它在任何一个示例中都没有使用案例。

标签: c++ templates function-templates template-argument-deduction


【解决方案1】:

对于foo&lt;int&gt;(a)ARG_T 是从 a 推导出来的,而不是从默认模板参数中获取的。由于它是按值函数参数,而aint 类型的表达式,因此推导为int

一般来说,当模板实参推导可以发现实参是什么时,不使用默认模板实参。

但是我们可以通过为函数参数引入非推导上下文来强制使用默认参数。例如:

template <class T, class ARG_T = T&>
T foo(std::enable_if_t<true, ARG_T> v1){
    //...
}

或 C++20 type_identity 实用程序,如其他答案所示。

【讨论】:

  • 对于那些还不明白的人:如果ARG_T可以推导出来,= T&amp;就完全被忽略了。
  • 这个问题的好答案,但如果你想推断出一个参考,为什么不只是template &lt;typename T&gt; T foo(T&amp;);
  • @sudo - 这将使T 可推演,它原本不是。
  • @StoryTeller 如果这是目标,那么我会选择 type_identity 而不使用第二个参数
  • @sudo - 第二个参数可能有更多用途。它作为实现函数的便捷类型别名。
【解决方案2】:

您需要从函数参数v 中为ARG_T 停止template argument deduction,(在std::type_identity 的帮助下,可用于将特定参数排除在推导之外);否则,将不会使用默认模板参数。例如

template <class T, class ARG_T = T&>
T foo(std::type_identity_t<ARG_T> v){
    return std::is_reference<decltype(v)>::value;
}

LIVE

顺便说一句:如果您的编译器不支持std::type_identity(C++20 起),您可以自己制作。

template<typename T> struct type_identity { typedef T type; };
template< class T >
using type_identity_t = typename type_identity<T>::type;

【讨论】:

  • 这个答案应该清楚地表明这是 C++20 的一个特性,这是 2019 年的,并且没有一个主要的现存编译器完全支持吹捧为 C++20 的特性。跨度>
猜你喜欢
  • 2014-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多