decltype 所需的不完整类型的派生到基数转换
Derived-to-base conversion for incomplete types required by decltype
我遇到了这个代码,涉及尾随返回类型和继承。
下面的最小示例使用 g++ 编译良好,而不是使用 clang
struct Base {};
int foo(Base&) {
return 42;
}
struct Derived : public Base {
auto bar() -> decltype(foo(*this)) {
return foo(*this);
}
};
int main()
{
Derived derived;
derived.bar();
return 0;
}
但是,如果我们auto bar() -> decltype(foo(*this))
更改为decltype(auto) bar()
(c++14 扩展),代码也会使用 clang 编译。链接到神霹雳 https://godbolt.org/z/qf_k6X .
谁能解释我
auto bar() -> decltype(return expression)
与decltype(auto) bar()
有何不同- 为什么编译器之间的行为不同
- 正确的实施是什么?
这是一个gcc 错误,尾随返回类型不在完整的类上下文中 [class.mem]
类的完整类上下文是
- 函数体,
- 默认参数,
- noexcept-specifier ([except.spec]),
- 合同条件,或
- 默认成员初始值设定项
我们看到,从 [conv.ptr] 派生到基数的转换需要一个完整的类
类型为"指向 cv D 的指针"的 prvalue(其中 D 是完整的类类型)可以转换为类型为"指向 cv B 的指针"的 prvalue,其中 B 是 D 的基类。
和 [dcl.init.ref]
如果可以通过标准转换序列将"指向 cv2 T2 的指针"类型的 prvalue 转换为"指向 cv1 T1 的指针"类型,则"cv1 T1"与"cv2 T2"的引用兼容。在使用两种类型的引用兼容关系来建立引用绑定的有效性并且标准转换序列格式不正确的所有情况下,需要这种绑定的程序都是格式不正确的。
另一方面,函数体位于完整的类上下文中,因此派生到基的转换是格式正确的。包含占位符类型(decltype(auto)
)的返回类型只要在使用它的表达式之前已经推导出来,它就有效。
对于 C++11 中可能的解决方法,您可以使用
auto bar() -> decltype(foo(std::declval<Base&>()))
{
return foo(*this);
}
只要你知道你想用Base
来称呼它。
我认为Clang拒绝这一点是错误的:
关于函数定义的返回类型,C++14 标准是这样说的:
[dcl.fct]/9]
不应在返回或参数类型中定义类型。参数的类型或返回类型 函数定义不应是不完整的类类型(可能是 CV 限定的),除非该函数被删除 (8.4.3)或该定义嵌套在该类的成员规范中(包括定义) 在类中定义的嵌套类中)。
在您的示例中,bar
的定义嵌套在class Derived
的成员规范中。所以这是允许的,GCC,ICC和MSVC做对了。
另一方面,decltype(auto)
工作,因为在需要函数的签名之前,实际上不会推导推导出的返回类型。 在您的情况下,当您在main
中调用bar()
时会发生这种情况。此时,class Derived
是完全定义的类型。叮当说得对。
请注意,即使使用auto
而不是decltype(auto)
也适用于您的示例。参见 Godbolt 上的演示。
- 在 C++ 中用派生类型重写成员函数
- 在 C++ 中将对象转换为派生类型
- C++如果采用类类型的函数被传递派生类型,有没有办法给出错误?
- 返回派生类型时出现协变类型错误
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- 基于派生类型的编译时行为分支
- 按类型排序向量并按类型或派生类型搜索
- 为什么"运算符<<"不适用于指向派生类型的成员?
- 无法返回派生类型的标准::unique_ptr<>
- 无法从派生类型的作用域访问另一个实例的受保护成员
- dynamic_cast到具有未知模板参数的派生类型
- 派生类型的成员
- 视觉C++ dynamic_cast返回 NULL,尽管对象是派生类型
- 在运算符中动态强制转换为派生类型<<
- 如何在不转换回基类类型的情况下返回派生类型的对象?
- 将派生指针分配给C 中的其他派生类型
- 如何将派生类型的对象放在用于基本类型的向量中
- C++ - 无法将派生类型作为基类型列表传递给构造函数
- 如何在基本类型参考中存储对派生类型的参考
- 统一处理具有协变类型的函数指针(如何使用派生类型调用回调?