【问题标题】:Using decay with perfect forwarding使用完美转发的衰减
【发布时间】:2020-04-13 00:48:35
【问题描述】:

假设我们有 2 个函数:

template <typename T> void callDecayExample1(T& t)
{
    std::initializer_list<T> testList2{ 1, 2, 3 };
}

template <typename T> void callDecayExample2(T&& t)
{
    std::initializer_list<std::decay_t<T>> testList{1, 2, 3};
}

我们这样称呼它们:

const int& i = 2;
int j = 10;
int& ref_j = j;

callDecayExample1(i);       // deduced as const int&
callDecayExample1(ref_j);// deduced as int&
callDecayExample1(j);   // deduced as int&

callDecayExample2(i);       // deduced as const int&
callDecayExample2(ref_j);// deduced as int&
callDecayExample2(j);   // deduced as int&

尽管两个函数的推导相似,但在第二个函数中,我必须使用 std::decay_t 来编译应用程序。为什么会这样?

我使用带有 /std:c++17 标志的 Visual Studio 2019

【问题讨论】:

  • 在第一种情况下,T 是非引用类型,即intconst int 对于这三种情况。在第二种情况下T,可以是引用类型,这会有所不同。您可以比较 decltype(t)T 来形象化这一点。
  • @Jarod42 抱歉,已更正

标签: c++ templates c++17 metaprogramming visual-studio-2019


【解决方案1】:

当你有类似的功能时

template <typename T> void callDecayExample1(T& t)
{
    std::initializer_list<T> testList2{ 1, 2, 3 };
}

那么T 只会被推断为非引用类型。如果你给它一个int&amp;,那么T就变成int,这样t就变成int&amp;。因此,您不需要使用decay

template <typename T> void callDecayExample2(T&& t)
{
    std::initializer_list<std::decay_t<T>> testList{1, 2, 3};
}

如果您传递int&amp;,则T 会被推断为int&amp;,然后引用折叠规则将int&amp; &amp;&amp; 转换为int&amp; 类型的t。这意味着如果没有decay,您将尝试创建一个您无法做到的std::initializer_list&lt;int&amp;&gt;

【讨论】:

  • 参考折叠,就是这样!
【解决方案2】:

说推导的类型相同是不正确的:

#include <iostream>

template <typename T>
void printType()
{
  std::cerr << __PRETTY_FUNCTION__ << std::endl;
}

template <typename T>
void callDecayExample1(T& t)
{
  printType<T>();
  std::initializer_list<T> testList2{1, 2, 3};
}

template <typename T>
void callDecayExample2(T&& t)
{
  printType<T>();
  std::initializer_list<std::decay_t<T>> testList{1, 2, 3};
}

int main()
{
  const int i = 0;
  int j = 1;
  int& ref_j = j;

  callDecayExample1(i);
  callDecayExample1(ref_j);
  callDecayExample1(j);

  callDecayExample2(i);
  callDecayExample2(ref_j);
  callDecayExample2(j);

  return 0;
}

打印:

void printType() [with T = const int]
void printType() [with T = int]
void printType() [with T = int]

void printType() [with T = const int&]
void printType() [with T = int&]
void printType() [with T = int&]

在您的情况下,std::decay 删除了第二个示例中存在的额外引用。

【讨论】:

  • 是的,或者 _ _FUNCSIG _ _ 用于 MSVC
【解决方案3】:

因为T 可能是也可能不是引用类型:

template <typename T> void callDecayExample2(T&& t)
{
    if constexpr (std::is_same<T, int&>::value)
        std::initializer_list<std::decay_t<T>> testList{ 1, 2, 3 };
    else
        std::initializer_list<T> testList{ 1, 2, 3 };
}

int val = 5;
callDecayExample2(5)   // T = int
callDecayExample2(val) // T = int&

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    • 2018-08-08
    相关资源
    最近更新 更多