为什么 auto return 类型推导适用于未完全定义的类型?
Why does auto return type deduction work with not fully defined types?
考虑以下几点:
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();
}
我想根据派生 class 中 operator()
的签名,使用 return 类型在 CRTP 基 class 中创建一个成员函数。但是 decltype(&Der::operator())
编译失败; Foo
中的 operator()
成员函数不可见。我认为这是因为基础 class 模板在 Foo
完全定义之前实例化了。
令人惊讶的是,如果我为 return 类型放置 auto
,它会编译。我假设 auto
会使编译器从函数体中推断出 return 类型并失败 - 因为函数体使用未完全定义的 Foo
类型。
此行为对于 MSVC 2015.3 和 Clang 3.8 都是相同的
为什么代码开始与 auto
一起工作? auto
类型推导是否以某种方式 "delay" 实例化?或者使用不同于手写 return 类型表达式的上下文?
你猜对了。推导的 return 类型在需要函数签名之前不会被实际推导。这意味着它将在调用 getCallOperator
的上下文中推导,此时 Foo
已完全定义。
这是在 7.1.6.4p12 中指定的:
Return type deduction for a function template with a placeholder in its declared type occurs when the definition is instantiated even if the function body contains a return statement with a non-type-dependent operand.
考虑以下几点:
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();
}
我想根据派生 class 中 operator()
的签名,使用 return 类型在 CRTP 基 class 中创建一个成员函数。但是 decltype(&Der::operator())
编译失败; Foo
中的 operator()
成员函数不可见。我认为这是因为基础 class 模板在 Foo
完全定义之前实例化了。
令人惊讶的是,如果我为 return 类型放置 auto
,它会编译。我假设 auto
会使编译器从函数体中推断出 return 类型并失败 - 因为函数体使用未完全定义的 Foo
类型。
此行为对于 MSVC 2015.3 和 Clang 3.8 都是相同的
为什么代码开始与 auto
一起工作? auto
类型推导是否以某种方式 "delay" 实例化?或者使用不同于手写 return 类型表达式的上下文?
你猜对了。推导的 return 类型在需要函数签名之前不会被实际推导。这意味着它将在调用 getCallOperator
的上下文中推导,此时 Foo
已完全定义。
这是在 7.1.6.4p12 中指定的:
Return type deduction for a function template with a placeholder in its declared type occurs when the definition is instantiated even if the function body contains a return statement with a non-type-dependent operand.