为什么 noexcept 说明符的作用域不在声明的方法内?
Why isn't the noexcept specifier scoped within the declared method?
尝试设计一些无异常类,我有一个与此类似的继承结构,但我发现 noexcept 说明符在使用成员函数时几乎没有帮助,因为说明符的范围不在函数内。
class Base
{
protected:
Base() noexcept {}
};
class Derived : public Base
{
public:
// error: 'Base::Base()' is protected
Derived() noexcept(noexcept(Base{})) : Base{} {}
// error: 'foo' was not declared in this scope
Derived(int) noexcept(noexcept(foo())) {}
// error: invalid use of 'this' at top level
Derived(float) noexcept(noexcept(this->foo())) {}
void foo() noexcept {}
};
演示
这也许是在 C++17 中得到改进的吗?尝试搜索此内容未产生相关结果。现在我已经放弃了一些非常丑陋(可能不正确)的尝试,例如 noexcept(noexcept(static_cast<Derived*>(nullptr)->foo()))
,但这对受保护的基类构造函数没有帮助。
目前是否可以声明引用像这样的受保护基类方法的 noexcept 说明符? noexcept(auto) 可能是相关的,但当然还不可能。我是否忽略了任何其他允许我包含此说明符的内容,或者在这种情况下我只需要省略它?
可以使用 Base 构造函数在作用域中的表达式来解决它,如下所示:
struct test_base : public Base {};
Derived() noexcept(noexcept(test_base())) : Base() {}
我相信你不能直接使用Base()
的原因与这个问题有关。
受保护的访问说明符的工作方式,它允许派生类 B 仅在以下情况下访问基类 A 的对象的内容 类 A 的对象是类 B 的子对象。这意味着唯一的 您可以在代码中执行的操作是通过访问 A 的内容 B:可以通过类型 B * 的指针访问 A 的成员(或 B型参考文献&)。但是您不能通过以下方式访问相同的成员 类型 A * 的指针(或引用 A &)。
这就像你有一个这样的成员函数一样:
void badfunc()
{
B b;
}
您正在尝试直接使用 Base
的构造函数,而不是通过 Derived
。当您在构造函数初始化列表中初始化基时,这是一个特殊的上下文,允许您调用构造函数,因为您是在初始化 Derived
的过程中执行此操作的。
这实际上是多个问题合二为一。
关于this
...
根据我的理解,this
的使用应该是完全多余的,但编译器对C++11的支持并不完全普遍。 根据 C++11 标准,这应该有效:
struct Base {
void func() noexcept;
};
struct Derived() {
void func() noexcept(noexcept(Base::func())) {}
};
请注意,base_func()
是一个非静态成员函数,但由于它出现在"未计算的操作数"中,所以没关系。 从 n3337 第 4.1.1 秒开始:
只能使用表示类的非静态数据成员或非静态成员函数的 id 表达式:
。
- 如果该 id-expression 表示非静态数据成员,并且它出现在未计算的操作数中。
但是,某些编译器不支持此功能。 然后,您将被迫使用std::declval
:
#include <utility>
struct Base {
void func() noexcept;
};
struct Derived() {
void func() noexcept(noexcept(std::declval<Base>().func())) {}
};
关于辅助功能...
我通读了标准中关于"未评估的操作数"和"成员访问控制"的相关部分,得出的结论是该标准有点模棱两可。 它提到protected
名称只能由成员、朋友和派生类使用。 问题是未计算的操作数是否"使用"出现在其中的成员名称。 他们当然不会使用成员名称,如果没有提供定义,甚至可以使用成员名称,而这种歧义正是术语"odr-use"甚至存在的原因! 例如
int f(); // No definition anywhere in program
int x = sizeof(f()); // Completely valid, even without definition of f
struct X {
X() = delete; // Cannot use this constructor
};
int xsize = sizeof(X{}); // Completely valid
尽管有些不清楚,但我很难想象C++委员会可能打算让您在未计算的操作数中使用已删除的成员函数,但不是无法访问的成员函数。 但是,我不确定。
请注意,上面的代码在 GCC 和 Clang 中编译时都没有错误。 但是,以下代码不是:
class X {
X(){}
};
class Y {
Y() = delete;
};
bool xokay = noexcept(X{}); // Error!
bool yokay = noexcept(Y{}); // Ok
GCC和Clang都接受Y,但不接受X,至少可以说这似乎有点奇怪。 以下代码被 Clang 接受,但不接受 GCC,使用 std::declval
无济于事:
class Base {
protected:
void func();
};
class Derived : public Base {
// Clang accepts this, GCC does not.
void func2() noexcept(noexcept(Base::func())) {}
};
真是一团糟。
结论
这里的结论是,似乎有很多不一致的地方需要解决,当前编译器和 C++11 规范之间也有很多差距。
- 将子类方法声明为基类的友元
- 模板中的模板方法 - 实例声明和类方法声明签名不同
- C++ C# 中的方法声明
- 使用gtest将所有方法声明为virtual以进行mocking
- 方法声明 c++ 后的引用符号
- 标题C 中的静态类方法声明
- 接口定义中的方法声明
- 如何在没有显式方法声明的情况下返回值
- C 类方法声明返回错误
- C++ dll 导入 VBA(Excel) 与方法声明"_Something"
- 查找没有定义的方法声明
- 只要调用的函数是用constexpr指定的,就将委托方法声明为constexpr
- mat类opencv中的begin()方法声明
- C++受模板方法声明影响的名称查找
- 我可以在Visual Studio 2012中将方法声明为朋友吗?
- 类中方法声明的顺序是否对编译器很重要
- 静态方法声明但未定义错误c++
- 错误:在类方法声明中无效地使用void表达式
- 奇怪的c++语法方法声明
- 类方法声明中的 decltype:在声明成员之前使用时出错"referenced"