在派生类中使用noexcept [英] Usage of noexcept in derived classes

查看:104
本文介绍了在派生类中使用noexcept的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在派生类上使用noexcept说明符时遇到问题,更确切地说,当父级是抽象类(具有protected构造函数)时.

I encounter an issue while using the noexcept specifier on derived classes, more precisely when the parent is an abstract class (has protected constructors).

此后是我声明类的示例.

Hereafter is an example of the way I declare my classes.

  • 在基类中具有public构造函数:一切正常.
  • protected相同的代码,派生的类不再不可移动".
  • With a public constructor in the base class: Everything is ok.
  • Same code with protected and the derived class is no more "nothrow movable".

我想念什么吗? std::is_nothrow_move_constructible是在派生类声明中使用的正确特征还是我应该使用其他东西?

Do I miss something? Is std::is_nothrow_move_constructible the correct traits to use in derived class declarations or should I use something else?

#include <cstdlib>
#include <iostream>

class BaseOk
{
public:
    BaseOk ( BaseOk&& other ) noexcept {}
};

class BaseNok
{
protected:
    BaseNok ( BaseNok&& other ) noexcept {}
};

class ChildOk : public BaseOk
{
public:
    ChildOk ( ChildOk&& other ) noexcept ( std::is_nothrow_move_constructible < BaseOk >::value )
        : BaseOk ( std::move ( other ) ) {}
};

class ChildNok : public BaseNok
{
public:
    ChildNok ( ChildNok&& other ) noexcept ( std::is_nothrow_move_constructible < BaseNok >::value )
        : BaseNok ( std::move ( other ) ) {}
};

int main ()
{
    std::cout << std::boolalpha;
    std::cout << "Is BaseOk   move constructible?         " << std::is_move_constructible < BaseOk >::value << '\n';
    std::cout << "Is ChildOk  move constructible?         " << std::is_move_constructible < ChildOk >::value << '\n';

    std::cout << '\n';
    std::cout << "Is BaseOk   nothrow move constructible? " << std::is_nothrow_move_constructible < BaseOk >::value << '\n';
    std::cout << "Is ChildOk  nothrow move constructible? " << std::is_nothrow_move_constructible < ChildOk >::value << '\n';

    std::cout << '\n';
    std::cout << "Is BaseNok  move constructible?         " << std::is_move_constructible < BaseNok >::value << '\n';
    std::cout << "Is ChildNok move constructible?         " << std::is_move_constructible < ChildNok >::value << '\n';

    std::cout << '\n';
    std::cout << "Is BaseNok  nothrow move constructible? " << std::is_nothrow_move_constructible < BaseNok >::value << '\n';
    std::cout << "Is ChildNok nothrow move constructible? " << std::is_nothrow_move_constructible < ChildNok >::value << '\n';
    std::cout << std::endl;

    return EXIT_SUCCESS;
}

输出:

 Is BaseOk   move constructible?         true
 Is ChildOk  move constructible?         true

 Is BaseOk   nothrow move constructible? true
 Is ChildOk  nothrow move constructible? true

 Is BaseNok  move constructible?         false
 Is ChildNok move constructible?         true

 Is BaseNok  nothrow move constructible? false
 Is ChildNok nothrow move constructible? false

___编辑____________________________________________________________

经过一段时间的搜索,并考虑到 Oleg Bogdanov 的麻烦,似乎无法将protected构造函数与noexcept ( is_nothrow_... )的用法结合使用.

After searching around for a while, and regarding to the andswer of Oleg Bogdanov, it unfortunately seems not possible to combine protected constructors with usage of noexcept ( is_nothrow_... ).

我正在编写抽象类,并声明了构造函数protected,仅出于文档目的.现在,构造函数又回到了public,但是我面临着另一个问题:

I was writting abstract classes and declared constructors protected for documentation purposes only. Now, constructors are back to public but I'm facing another problem:

由于不能实例化一个抽象类,所以std::is_nothrow_move_constructible<BaseClass>返回false,并且所有派生类都不能被标记为不抛出异常,即使它们不是.

As an abstract class cannot be instanciated, std::is_nothrow_move_constructible<BaseClass> returns false and all derived classes can never be tagged as not throwing exceptions even if they are not.

请参见下面的示例:

#include <cstdlib>
#include <iostream>

class Foo
{
public:
    Foo ( Foo&& other ) noexcept {}
    virtual ~Foo () = 0;  // Removing '= 0' makes both outputs print 'true'.
};
Foo::~Foo () {}

class Bar : public Foo
{
public:
    Bar ( Bar&& other ) noexcept ( std::is_nothrow_move_constructible < Foo >::value )
        : Foo ( std::move ( other ) ) {}
};

int main ()
{
    std::cout << std::boolalpha;
    std::cout << "Foo: " << std::is_nothrow_move_constructible < Foo >::value << '\n';
    std::cout << "Bar: " << std::is_nothrow_move_constructible < Bar >::value << '\n';

    return EXIT_SUCCESS;
}

输出:

Foo: false
Bar: false

推荐答案

在评估true is_constructible 的工作原理完全相同,

When evaluating to true is_move_constructible works exactly like is_constructible, which in turn says that

T是对象或引用类型,变量定义T obj(std :: declval()...);格式正确

T is an object or reference type and the variable definition T obj(std::declval()...); is well-formed

我的猜测是,在您的情况下,定义BaseNok obj(...)并不是真正的格式正确的,因为您既没有公开的默认ctor(隐式删除了它),也没有任何其他可访问的ctor(没有受保护的ctor) ),因此等于false. (不过,良好形式的定义本身是有争议的)

My guess is that in your case, definition BaseNok obj(...) is not really well-formed, because you neither have public default ctor (its implicitly removed) nor any other accessible ctor (protected is not), thus it evals to false. (The definition of well-formeness itself is arguable though)

ChildNok仍然是move_constructible的,因为您公开了它的移动ctor,其他情况也恰好是false的原因,因为std::is_move_constructible < BaseNok >::value已经是false

ChildNok is still move_constructible because you made its move ctor public, other cases eval to false exactly because std::is_move_constructible < BaseNok >::value is already false

至于已编辑的问题, is_constructible note 部分提到

As for edited question, note section of is_constructible mentions

在许多实现中,is_nothrow_constructible还检查析构函数是否抛出异常,因为它实际上是noexcept(T(arg))

In many implementations, is_nothrow_constructible also checks if the destructor throws because it is effectively noexcept(T(arg))

当您将析构函数保持为纯虚拟时,它可能无法通过检查.

When you keep your destructor pure virtual, it probably fails the check.

我个人不确定这是类型特征的疏忽还是设计, LWG问题2116

I am personally not sure if it's oversight or by-design of type traits, some issues are covered in LWG issue 2116

我不是在这里提出可扩展的解决方案,但是鉴于基数也是noexcept(),为什么现在不无条件地标记派生类为noexcept

I'm not proposing a scalable solution here, but why would not you mark your derived classes unconditionally noexcept for now, given that base is noexcept() too

这篇关于在派生类中使用noexcept的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆