【问题标题】:Can a non-throwing function pointer point to a throwing-function?非抛出函数指针可以指向抛出函数吗?
【发布时间】:2021-06-08 23:06:48
【问题描述】:

在关于noexcept 异常规范的 C++ Primer 中,据说指向可能会隐式抛出的函数的指针(在没有异常规范的情况下定义,例如: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';
}
  • 当我针对-std=c++17-std=c++2a 编译程序时,它可以正常工作,所以我得到了我在cmets 行中所写的错误。但是当我针对-std=c++11-std=c++14 进行编译时,它们都可以正常工作并且编译器不会抱怨?!

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

【问题讨论】:

  • 它可能在 C++14 及更低版本中未指定。然后有人注意到了差异,他们收紧了 C++17 的要求。
  • 如果您知道您的报价来自标准的哪个部分,您可以将其与标准的先前版本进行比较,看看它是否存在。
  • 看起来像一个 GCC 错误,Clang and MSVC reject it,根据cppreference,即使在 C++17 之前它也应该是一个错误。
  • 这句话(带有快速二进制印章)似乎已在2015-11-09 中添加到N4567 之前的版本n4527 似乎没有该措辞。我在[conv.fctptr] 部分找到了它
  • 看起来在C++14中,noexcept-ness不是函数类型的一部分,所以pFn1pFn2pFn3pFn4的声明都是除标识符外等价。 ([dcl.fct],尤其是第 1-2 段和第 6 段中的最后一个规范句)

标签: c++ function-pointers noexcept


【解决方案1】:

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

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

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

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

G++ 没有给出 p5 中的例子的错误:

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
}

这在 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
}

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

【讨论】:

    猜你喜欢
    • 2018-04-07
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 2015-12-28
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多