Я боролся с проблемой компиляции и смог сократить проблему до небольшого сегмента кода.
Чтобы подготовить почву, я пытаюсь выполнить CRTP, где базовый метод вызывает другой в производном классе. Сложность в том, что я хочу использовать конечные возвращаемые типы, чтобы получить тип пересылки непосредственно в метод производного класса. Это всегда не удается скомпилировать , если я не пересылаю вызов оператору вызова в производном классе.
Это компилирует:
#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;
}
Хотя это не так: (обратите внимание на комментарий для единственной разницы)
#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;
}
Я получаю ошибку:
<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&&>()...));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
Похоже, что во время разрешения decltype в классе Derived происходит какое-то особое поведение. Есть ли в стандарте что-то, что могло бы это объяснить?
РЕДАКТИРОВАТЬ: Сделано еще большее упрощение
PS: пример компиляции на godbolt: https://godbolt.org/g/St2gYC
std::declval<Blah>()? Я предполагаю, что второй блок - это случайное использованиеIncomplete, а первый - нет. - person Passer By   schedule 05.08.2017