【问题标题】:How to keep cv qualifier or reference in return type deduction in c++1y?如何在 c++1y 的返回类型推导中保留 cv 限定符或引用?
【发布时间】:2013-05-30 02:32:59
【问题描述】:

首先我构造了四个结构体,每个结构体返回值、左值引用、常量左值引用、右值引用。我在包装器中使用它们(BC),在这些包装器的方法 func() 中, 我想保留 func() 的引用和 cv 限定符 A

在 c++11 中,我使用了尾随返回类型。但是随着c++14中正常返回类型推导的到来,我猜我可以跳过尾部,但只有auto,返回类型会像普通的auto一样忽略限定符和引用。

然后,我的问题是在 c++14 中实现它的最佳方法是什么,它的行为就像下面的 B 类? 在琐碎的时候写尾部(通常是decltype(返回表达式))有时会令人沮丧。

struct A1 {
    int func(){
        return x;
    }
    int x{3};
};

struct A2 {
    int& func(){
        return x;
    }
    int x{3};
};

struct A3 {
    const int& func(){
        return x;
    }
    int x{3};
};

struct A4 {
    int&& func(){
        return std::move(x);
    }
    int x{3};
};

template <class A>
struct B{
    auto func() -> decltype(std::declval<A>().func())
    {
        return a.func();
    }

    A a;
};

template <class A>
struct C{
    auto func()
    {
        return a.func();
    }

    A a;
};

int main(){
    std::cout << std::boolalpha;

    B<A1> b1;   
    B<A2> b2;   
    B<A3> b3;   
    B<A4> b4;

    static_assert(std::is_same<decltype(b1.func()), int>::value, "true");
    static_assert(std::is_same<decltype(b2.func()), int&>::value, "true");
    static_assert(std::is_same<decltype(b3.func()), const int&>::value, "true");
    static_assert(std::is_same<decltype(b4.func()), int&&>::value, "true");

    C<A1> c1;   
    C<A2> c2;   
    C<A3> c3;   
    C<A4> c4;

    static_assert(std::is_same<decltype(c1.func()), int>::value, "true");
    static_assert(std::is_same<decltype(c2.func()), int>::value, "true");
    static_assert(std::is_same<decltype(c3.func()), int>::value, "true");
    static_assert(std::is_same<decltype(c4.func()), int>::value, "true");
}

请注意,这个程序在 gcc 4.8 中使用 -std=c++1y 选项编译没有问题。

【问题讨论】:

标签: c++ c++11 c++14


【解决方案1】:

针对 C++14 的提议包括一个(N3638,Jason Merrill),它定义了一个特殊声明来实现这一点,使用 decltype(auto) 而不是 auto

template <class A>
struct C{
  decltype(auto) func()
    {
        return a.func();
    }

    A a;
};

GCC 在 4.9 snapshot 中实现了这一点,请参阅 C++ 部分。

将代码的最后部分更改为

static_assert(std::is_same<decltype(c1.func()), int>::value, "true");
static_assert(std::is_same<decltype(c2.func()), int&>::value, "true");
static_assert(std::is_same<decltype(c3.func()), const int&>::value, "true");
static_assert(std::is_same<decltype(c4.func()), int&&>::value, "true");

GCC 4.9 快照编译它,而 4.8 没有。

(注意:如果您在编译时使用-g 选项,两个编译器都会因内部编译器错误而崩溃。这是由于Bug 56014。)


为了完整起见,以下是提案中最相关的部分:

如果占位符是 decltype(auto) 类型说明符,则变量的声明类型或函数的返回类型应仅是占位符。为变量或返回类型推导的类型如 7.1.6.2 中所述确定,就好像初始化器是 decltype 的操作数一样。 [ 例子:

int i;
int&& f();
auto           x3a = i;        // decltype(x3a) is int
decltype(auto) x3d = i;        // decltype(x3d) is int
auto           x4a = (i);      // decltype(x4a) is int
decltype(auto) x4d = (i);      // decltype(x4d) is int&
auto           x5a = f();      // decltype(x5a) is int
decltype(auto) x5d = f();      // decltype(x5d) is int&&
auto           x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto          *x7a = &i;       // decltype(x7a) is int*
decltype(auto)*x7d = &i;       // error, declared type is not plain decltype(auto)

—结束示例]

【讨论】:

  • 哦,我明白了。谢谢你。所以我必须等到 gcc 4.9。:) decltype(auto) 似乎很有用!!。
  • @Sungmin 确实。出于实验目的,如果您愿意自己构建,可以使用 4.9 快照。快照可从所有GCC source code mirrors 获得。
猜你喜欢
  • 2014-03-05
  • 1970-01-01
  • 1970-01-01
  • 2016-09-23
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
  • 2015-09-19
  • 1970-01-01
相关资源
最近更新 更多