I've been struggling with a compilation issue, and have been able to shrink the problem down to a small code segment.
To set the stage, I'm trying to do CRTP, where the base method calls another in the derived class. The complication is, I want to use trailing return types to get the type of forwarding directly to the the Derived class's method. This always fails to compile unless I forward to the call operator in the 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;
}
While this does not: (note comment for the only 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 get:
<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 seems to be some special behavior going on during resolution of the decltype in the Derived class. Is there something in the standard that would explain this?
EDIT: Made an even bigger simplification
PS: compiling example on godbolt: https://godbolt.org/g/St2gYC
std::declval<Blah>()
? I'd guess that the second block is an odr use ofIncomplete
while the first is not. – Tartuffery