【问题标题】:Remove reference in decltype (return T instead of T& where T& is the decltype)删除 decltype 中的引用(返回 T 而不是 T&,其中 T& 是 decltype)
【发布时间】:2012-10-23 12:41:22
【问题描述】:

(如果您是 C++11 专业人士,请跳至粗体段落。)

假设我想编写一个模板方法,该方法调用并返回传递的对象的结果,该对象的类型是模板参数:

template<ReturnType, T>
ReturnType doSomething(const T & foo) {
    return foo.bar(); // EDIT: Might also be an expression introducing a temp val
}

所以T 必须有一个方法ReturnType T::bar() const 才能在这样的调用中使用:

struct MyClass {
    ...
    int bar() const;
    ...
};
...
MyClass object;
int x = doSomething<int, MyClass>(object);

由于类型推导,我们不必写MyClass,调用变为:

int x = doSomething<int>(object);

但是省略 &lt;int&gt; 也会导致编译错误,因为该方法不需要返回 int 以便之后分配给 x(例如,它可以返回 char)。

在 C++0x/11 中,我们可以使用 autodecltype 来推断模板方法的返回类型:

template<T>
auto doSomething(const T & foo) -> decltype(foo.bar()) {
    return foo.bar(); // EDIT: Might also be an expression introducing a temp val
}

编译器现在将找出foo.bar() 的类型,并将其用作返回类型。对于我们的具体类MyClass,这将是一个int,以下内容就足够了:

int x = doSomething(object);

现在我的问题是:

如果 MyClass 将 bar() 定义为返回 int&amp;,则 doSomething(object) 的返回类型也将是 int&amp; = decltype(foo.bar())。这是一个问题,因为 G++ 现在符合我返回对临时的引用

我该如何解决这个问题?有没有像remove_reference 这样可以像remove_reference(decltype(foo.bar())) 这样使用的东西?

我想过只声明一个辅助方法,它接受T&amp; 并返回T,然后将doSomething 的返回类型定义为decltype(helper(foo.bar()))。但必须有更好的方法,我感觉到了。

【问题讨论】:

  • 这是怎么回事?您所要做的就是传递参考。是的,有std::remove_reference&lt;T&gt;::type
  • @GManNickG 我不想在我的程序中出现警告。我想用-Werror -Wall 编译。感谢std::remove_reference 的提示,我知道我以前见过这个,但是在搜索“c++11 模板类型推导删除参考”时在 google 上找不到它,可能是我的搜索过于本地化了 :)
  • 不,我是说根本不应该有警告。如果foo.bar() 返回一个引用,您应该也可以将它作为引用返回。
  • 啊,是的,在这种情况下。 foo.bar() 是一个不好的例子,比如说return foo.bar() + 1。在我的情况下,我正在使用迭代器并想推断出具有begin() 的提供容器类型的T,所以我的decltype 是decltype(*container.begin()),即T&amp;。由于我返回了一个临时的 T 我需要删除引用。
  • 很公平,我将把这个区别添加到我的答案中。

标签: c++ templates c++11 type-deduction


【解决方案1】:

要删除引用:

#include <type_traits>

static_assert(std::is_same<int, std::remove_reference<int&>::type>::value, "wat");

在你的情况下:

template <typename T>
auto doSomething(const T& foo)
    -> typename std::remove_reference<decltype(foo.bar())>::type
{
    return foo.bar();
}

为了清楚起见,请注意,返回引用就可以了:

#include <type_traits>

struct f
{
    int& bar() const
    {
        static int i = 0;
        return i;
    } 
};

template <typename T>
auto doSomething(const T& foo)
    -> decltype(foo.bar())
{ 
    return foo.bar();
}

int main()
{
    f x;
    return doSomething(x);
}

返回的引用可以简单地传递而不会出错。您在评论中的示例变得重要且有用:

template <typename T>
auto doSomething(const T& foo)
    -> decltype(foo.bar())
{ 
    return foo.bar() + 1; // oops
}

【讨论】:

  • 在C++14中,也可以使用std::remove_reference_t&lt;int&amp;&gt;
  • @Kupiakos 在 C++14 中,您可以使用没有尾随 decltype 的自动返回类型。
  • @AlyssaHaroldsen 我在std::remove_reference_t 上找不到太多文档。这与std::remove_reference 有何不同?
  • std::remove_reference_t 等价于std::remove_reference::type。这是一种简写方式,类似于std::remove_reference_v,其中_v 表示::value
猜你喜欢
  • 2022-12-21
  • 1970-01-01
  • 2023-03-28
  • 2017-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多