std::declval vs crtp, cannot deduce method return type from incomplete type
Asked Answered
T

1

12

I am trying to do something like this (in c++11):

#include <utility>

template <typename T>
struct base {
    using type = decltype( std::declval<T>().foo() );
};

struct bar : base<bar> {
    int foo() { return 42;}
};

int main() {
    bar::type x;
}

which fails with

prog.cc: In instantiation of 'struct base<bar>':
prog.cc:8:14:   required from here
prog.cc:5:46: error: invalid use of incomplete type 'struct bar'
     using type = decltype( std::declval<T>().foo() );
                            ~~~~~~~~~~~~~~~~~~^~~
prog.cc:8:8: note: forward declaration of 'struct bar'
 struct bar : base<bar> {
        ^~~

How can I declare an alias to the return type of bar::foo in base ? Is it not possible?

This question seems to be rather related: Special behavior for decltype of call operator for incomplete types, though I couldnt manage to apply the answer given there to my case.

Tl answered 7/6, 2019 at 16:7 Comment(0)
O
13

You can make type a template type alias, so that users can instantiate it after the definition of bar is available. This will change the final syntax from bar::type to bar::type<>.

template <typename T>
struct base {
    template <typename G = T>
    using type = decltype( std::declval<G>().foo() );
};

struct bar : base<bar> {
    int foo() { return 42;}
};

int main() {
    bar::type<> x;
}

live example on godbolt.org

Orpah answered 7/6, 2019 at 16:22 Comment(2)
I think now I also understand the reasoning in the answer I linked :) I dont like the bar::type<> too much but I could live with thatTl
Unfortunately, type<> is not that useful inside a class scope. E.g., you can't write type<> foo2(); for a base's of bar's member function without using similar G = T trick.Abramabramo

© 2022 - 2024 — McMap. All rights reserved.