Special behavior for decltype call statement for incomplete types

I struggled with the compilation problem and was able to reduce the problem to a small segment of code.

To set up the scene, I am trying to do CRTP where the base method calls another in a derived class. The complication is that I want to use return types to get the forwarding type directly to the Derived class method. This always fails to compile unless you pass a call statement in a derived class.

This compiles:

#include <utility>

struct Incomplete;

template <typename Blah>
struct Base
{
    template <typename... Args>
    auto entry(Args&&... args)
        -> decltype(std::declval<Blah&>()(std::declval<Args&&>()...));
};

void example()
{
    Base<Incomplete> derived;
}

Until this happens: (note the comment only for difference)

#include <utility>

struct Incomplete;

template <typename Blah>
struct Base
{
    template <typename... Args>
    auto entry(Args&&... args)
        -> decltype(std::declval<Blah&>().operator()(std::declval<Args&&>()...));
        //             I only added this ^^^^^^^^^^^
};

void example()
{
    Base<Incomplete> derived;
}

The error I am getting is:

<source>: In instantiation of 'struct Base<Incomplete>':
15 : <source>:15:22:   required from here
10 : <source>:10:58: error: invalid use of incomplete type 'struct Incomplete'
         -> decltype(std::declval<Blah&>().operator()(std::declval<Args&&>()...));
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

There appears to be some special behavior when decltype resolves in the Derived class. Is there anything in the standard that could explain this?

EDIT:

PS: godbolt: https://godbolt.org/g/St2gYC

+6
1

- ([temp.inst]/2).

template <typename... Args>
auto entry(Args&&... args)
    -> decltype(std::declval<Incomplete&>().operator()(std::declval<Args&&>()...));

[temp.res]/10:

( 14.6.2), ( ) , ;

, operator() . , . , , , .

, Incomplete. x(...), x , x.operator()(...) , operator() x — [over.call]:

, x(arg1,...) x.operator() (arg1,...) x T , T​::​operator()(T1, T2, T3) ([over.match.best]).

, : [temp.res]/10 , . , ( ...) , operator(), ; .operator(), , . [temp.dep]:

, . [...]

operator() .

+4

All Articles