非抛出函数指针可以指向抛出函数吗?

Mae*_*tro 7 c++ function-pointers noexcept

在关于异常规范的 C++ Primer 上noexcept,据说指向可能抛出隐式(没有异常规范定义,例如:)void(*p)();或显式(void(*p)() noexcept(false);)的函数的指针可以指向任何函数,甚至指向不抛出的函数。

另一方面,一个不能抛出异常的函数指针(noexcept例如void(*p) noexcept;)只能指向一个不会抛出异常的函数。

我发现这非常合乎逻辑,因为第一个指针可以从抛出函数指针指向非抛出函数,而第二个指针也很合乎逻辑。

我尝试过这个来了解更多:

void func1(){ // may throw
    std::cout << "func1()\n";
}

void func2() noexcept(false){ // may throw
    std::cout << "func2()\n";
}

void func3() noexcept(true){ // won't throw
    std::cout << "func3()\n";
}

void func4() noexcept{ // won't throw
    std::cout << "func4()\n";
}


int main(int argc, char* argv[]){

    void(*pFn1)();
    pFn1 = func1; // OK
    pFn1 = func2; // OK
    pFn1 = func3; // OK
    pFn1 = func4; // OK

    void(*pFn2)() noexcept(false);
    pFn2 = func1; // OK
    pFn2 = func2; // OK
    pFn2 = func3; // OK
    pFn2 = func4; // OK

    void(*pFn3)() noexcept(true);
    pFn3 = func1; // Error on C++ 17 and above. OK on C++11 and 14
    pFn3 = func2; // Error on C++ 17 and above. OK on C++11 and 14
    pFn3 = func3; // OK
    pFn3 = func4; // OK

    void(*pFn4)() noexcept(true);
    pFn4 = func1; // Error on C++ 17 and above. OK on C++11 and 14
    pFn4 = func2; // Error on C++ 17 and above. OK on C++11 and 14
    pFn4 = func3; // OK
    pFn4 = func4; // OK

    std::cout << '\n';
}
Run Code Online (Sandbox Code Playgroud)
  • 当我针对 编译程序时-std=c++17-std=c++2a它会正常工作,因此我会收到我在注释行中所写的错误。但是当我编译时-std=c++11-std=c++14我让它们全部工作并且编译器不会抱怨?!

这是否意味着标准已经改变?谢谢你!

Jon*_*ely 2

它在 C++17 中格式不正确,因为它noexcept是类型系统的一部分,并且没有从指向潜在抛出函数的指针到指向非抛出函数的指针的转换。

在 C++17 之前,相关规则是 [ except.spec] p5:

类似的限制适用于函数指针、成员函数指针和函数引用的赋值和初始化:目标实体应至少允许赋值或初始化中源值允许的异常。

因此,尽管noexcept不是类型系统的一部分,但 OP 的分配格式不正确。

对于 p5 中的示例,G++ 不会给出错误:

class A { /* ... */ };
void (*pf1)(); // no exception specification
void (*pf2)() throw(A);

void f() {
  pf1 = pf2; // OK: pf1 is less restrictive
  pf2 = pf1; // error: pf2 is more restrictive
}
Run Code Online (Sandbox Code Playgroud)

这在 C++98/11/14 中应该是格式错误的。

与 noexcept 说明符等效的内容是:

class A { /* ... */ };
void (*pf1)(); // no exception specification
void (*pf2)() noexcept;

void f() {
  pf1 = pf2; // OK: pf1 is less restrictive
  pf2 = pf1; // error: pf2 is more restrictive
}
Run Code Online (Sandbox Code Playgroud)

G++ 在 98/11/14 中不拒绝这一点,只有 C++17 及更高版本才拒绝。