Reputation: 2572
On C++ Primer on noexcept
exception specification, it is said that a pointer to a function that may throw Implicitly (defined without exception specification e.g: void(*p)();
) or explicitly (void(*p)() noexcept(false);
) may point to any function even to a non-throwing function.
On the other hand a function pointer which may not throw (noexcept
e.g void(*p) noexcept;
) can only point to a function that won't throw.
I found that very logical because the first pointer it is OK to point to a non-throwing function from a throwing function pointer and the second too is so logical.
I've tried this to understand more:
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
it works as it should so I get the errors as I've written in the lines comments. But when I compile against -std=c++11
, -std=c++14
I get them all work and the compiler doesn't complain?!Does this mean the standard has changed? Thank you!
Upvotes: 7
Views: 262
Reputation: 171393
It's ill-formed in C++17 because the noexcept
is part of the type system, and there is no conversion from a pointer to a potentially-throwing function to a pointer to a non-throwing function.
Before C++17 the relevant rule is [except.spec] p5:
A similar restriction applies to assignment to and initialization of pointers to functions, pointers to member functions, and references to functions: the target entity shall allow at least the exceptions allowed by the source value in the assignment or initialization.
So although the noexcept
isn't part of the type system, the OP's assignments are ill-formed.
G++ does not give an error for the example in 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
}
That should be ill-formed in C++98/11/14.
The equivalent with a noexcept-specifier would be:
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++ doesn't reject this in 98/11/14, only C++17 and up.
Upvotes: 2