【问题标题】:How to correctly propagate the type of a universal reference?如何正确传播通用引用的类型?
【发布时间】:2015-12-07 19:57:16
【问题描述】:

我的代码库中有一种情况,我必须实现std::get() 的通用形式,它适用于任何类型的元组类型。该函数接受对Tuple 的通用引用,并返回对TupleIth 元素的引用。我不知道如何命名引用的类型。不幸的是,我无法使用 auto 返回类型,只能让编译器自己解决。

这是我的第一次尝试:

#include <type_traits>
#include <tuple>

template<class T, class U>
struct propagate_reference
{
  using type = U;
};

template<class T, class U>
struct propagate_reference<T&,U>
{
  using type = typename std::add_lvalue_reference<U>::type;
};

template<class T, class U>
struct propagate_reference<T&&,U>
{
  using type = typename std::add_rvalue_reference<U>::type;
};

template<size_t I, class TupleReference>
struct get_result
{
  using tuple_type = typename std::decay<TupleReference>::type;

  using type = typename propagate_reference<
    TupleReference,
    typename std::tuple_element<I,tuple_type>::type
  >::type;
};

template<size_t I, class Tuple>
typename get_result<I,Tuple&&>::type my_get(Tuple&& t)
{
  return std::get<I>(std::forward<Tuple>(t));
}

int foo(const std::tuple<int>& t)
{
  return my_get<0>(t);
}

int main()
{
  return 0;
}

Clang 拒绝这个程序:

$ clang -std=c++11 test_get.cpp 
test_get.cpp:36:10: error: binding of reference to type 'int' to a value of type 'const __tuple_element_t<0UL, tuple<int> >' (aka 'const int') drops qualifiers
  return std::get<I>(std::forward<Tuple>(t));
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test_get.cpp:41:10: note: in instantiation of function template specialization 'my_get<0, const std::tuple<int> &>' requested here
  return my_get<0>(t);
         ^
1 error generated.

我怀疑问题出在我实例化get_result 的方式上。我做错了什么?

【问题讨论】:

  • 为什么无法自动返回?
  • 这是你需要remove_reference而不是decay的地方。
  • 究竟有什么不适用于std::get
  • “我不能使用汽车”是什么意思?你有“-std=c++11”——这表明你可以以 C++11 方式使用auto,但不能以 C++14 方式使用。您还有其他限制 - 一些编码标准吗?
  • @PiotrNycz:是的,我还有其他限制。我知道通常可以进行返回类型扣除。我有兴趣了解为什么我最初的尝试不起作用。

标签: c++ perfect-forwarding universal-reference


【解决方案1】:

问题在于std::decay 删除了 cv-qualifiers,并将生成的类型定义为成员 typedef 类型。正如 TC 在 cmets 中已经提到的,您在这里需要的是 std::remove_reference

template<size_t I, class TupleReference>
struct get_result
{
  using tuple_type = typename std::remove_reference<TupleReference>::type;

  using type = typename propagate_reference<
    TupleReference,
    typename std::tuple_element<I,tuple_type>::type
  >::type;
};

Live Demo

【讨论】:

    猜你喜欢
    • 2011-03-20
    • 1970-01-01
    • 2020-05-23
    • 2018-10-22
    • 2018-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多