如何在c ++ 1y中保留cv限定符或引用的返回类型推导?

Sun*_*min 5 c++ c++11 c++14

首先,我构造了四个结构,每个结构返回值,l值引用,const l值引用,r值引用.我使用他们的包装(BC),在方法func()的包装的,我想保持引用和CV预选赛func()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");
}
Run Code Online (Sandbox Code Playgroud)

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

jog*_*pan 10

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

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

    A a;
};
Run Code Online (Sandbox Code Playgroud)

GCC在4.9快照中实现了这一点,请参阅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");
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

- 结束例子]