请考虑以下事项:
template<typename Der>
struct Base {
// NOTE: if I replace the decltype(...) below with auto, code compiles
decltype(&Der::operator()) getCallOperator() const {
return &Der::operator();
}
};
struct Foo : Base<Foo> {
double operator()(int, int) const {
return 0.0;
}
};
int main() {
Foo f;
auto callOp = f.getCallOperator();
}
我想在CRTP基类中创建一个成员函数,其返回类型取决于派生类中operator()
的签名。但是decltype(&Der::operator())
无法编译; operator()
中的Foo
成员函数不可见。我假设这是因为在完全定义Foo
之前实例化了基类模板。
令人惊讶的是,如果我将auto
放置为它编译的返回类型。我假设auto
会使编译器从函数体中推断出返回类型并失败 - 因为正文使用了未完全定义的Foo
类型。
MSVC 2015.3和Clang 3.8的行为相同
为什么代码开始使用auto
?是auto
以某种方式输入扣除&#34;延迟&#34;实例化?或者使用与手写返回类型表达式不同的上下文?
答案 0 :(得分:24)
你的猜测是正确的。在需要函数签名之前,实际上不推导推导出的返回类型。这意味着它将在调用getCallOperator
的上下文中推断出来,此时Foo
已完全定义。
这在7.1.6.4p12中指定:
当实例化定义时,即使函数体包含带有非类型相关操作数的return语句,也会在其声明类型中使用占位符的函数模板返回类型推导。