質問

First I construct four structs each of which returns value, l-value reference, const l-value reference, r-value reference. And I use them in the wrapper(B or C), in the method func() of those wrapper, I want to keep the references and cv qualifiers of func() of A.

In c++11, I used trailing return type. But with the arrival of the normal return type deduction in c++14, I guessed I can skip the trailing part, but only with auto, the return type ignores qualifiers and references just like ordinary auto.

Then, my question is what is the best way to achieve it in c++14 which behaves just like class B below? It is sometimes depressive to write trailing part(usually decltype(return expression)) when it is trivial.

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");
}

Note that this programs compiles without problem in gcc 4.8 with -std=c++1y option.

役に立ちましたか?

解決

The proposals for C++14 include one (N3638, by Jason Merrill) that defines a special declaration to accomplish this, using decltype(auto) instead of auto:

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

    A a;
};

GCC implements this in the 4.9 snapshot, see the C++ section.

When changing the final parts of your code to

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");

the GCC 4.9 snapshot compiles it, while 4.8 does not.

(Note: Both compilers will crash on an internal compiler error if you use the -g option when compiling. This is due to Bug 56014.)


For the sake of completeness, here is the most relevant section from the proposal:

If the placeholder is the decltype(auto) type-specifier, the declared type of the variable or return type of the function shall be the placeholder alone. The type deduced for the variable or return type is determined as described in 7.1.6.2, as though the initializer had been the operand of the decltype. [ Example:

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)

— end example ]

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top