Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create an alias for a noexcept function pointer?

I'd like to do this:

using function_type = void (*)(void*)noexcept;

But I get an error "exception specifications are not allowed in type aliases." (clang in version 6.1 of Xcode)

Is there a workaround to create an alias with a noexcept specifier?

I'm looking for something that works as defined by the language (not an extension) for cross-platform capabilities.

like image 971
Michael Gazonda Avatar asked Dec 15 '14 17:12

Michael Gazonda


People also ask

What is Noexcept specifier in C++?

noexcept specifier(C++11) noexcept operator(C++11) Dynamic exception specification(until C++17) [edit] Specifies whether a function could throw exceptions.

What happens if a Noexcept function throws?

When an exception is thrown from a function that is declared noexcept or noexcept(true) , std::terminate is invoked. When an exception is thrown from a function declared as throw() in /std:c++14 mode, the result is undefined behavior. No specific function is invoked.

Can we create a pointer to a member function?

To point to a static class member, you must use a normal pointer. You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions.


4 Answers

The standard explicitly forbids an exception specification from appearing in a typedef or an alias declaration. But it also states that the exception specifier may appear in a function pointer type.

§15.4/2 [except.spec]

An exception-specification shall appear only on a function declarator for a function type, pointer to function type, reference to function type, or pointer to member function type that is the top-level type of a declaration or definition, or on such a type appearing as a parameter or return type in a function declarator. An exception-specification shall not appear in a typedef declaration or alias-declaration.

And if a pointer to function does have an exception specification, then that function pointer must always be assigned a function type that has a compatible exception specification.

§15.4/5

... 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. ...

Using these two, you can get the noexcept specification into the function pointer type in a roundabout fashion.

void (*foo_ptr)(void *) noexcept = nullptr;
using function_type = decltype(foo_ptr);

Now, you cannot assign a function without a noexcept(true) specification to a function pointer of type function_type. clang will fail to compile the code with the error

error: target exception specification is not superset of source

like image 125
Praetorian Avatar answered Oct 01 '22 17:10

Praetorian


An alternative to Praetorian's answer, which doesn't involve declaring a variable:

void unused_function(void*)noexcept;
using function_type = decltype(&unused_function);

The unused_function is declared, but not defined.

like image 27
Michael Gazonda Avatar answered Oct 02 '22 17:10

Michael Gazonda


As a corollary to this answer, the pattern you seek is, simply:

using function_type = decltype(std::declval<function_type_declaration>());

I.e.

#include <utility>
//...
using function_type = decltype(std::declval<void (*)(void*)noexcept>());

This does not work with extern linkage, including extern "C", i.e.:

// INVALID
using function_type = decltype(std::declval<extern "C" void(*)(void)>());

// WORKAROUND
extern "C" void function_type_dummy(void);
using function_type = decltype(&function_type_dummy);
like image 29
Kuba hasn't forgotten Monica Avatar answered Oct 02 '22 17:10

Kuba hasn't forgotten Monica


As a further simplification of this answer, we can use the type trait std::add_pointer as follows:

using function_type = std::add_pointer_t<void(void*) noexcept>;

From the cppreference documentation (emphasis mine):

If T is a reference type, then provides the member typedef type which is a pointer to the referred type.

Otherwise, if T names an object type, a function type that is not cv- or ref-qualified, or a (possibly cv-qualified) void type, provides the member typedef type which is the type T*.

Otherwise (if T is a cv- or ref-qualified function type), provides the member typedef type which is the type T.

In other words, std::add_pointer is implemented in such a way that it's compatible with Function signature-like expressions as C++ template arguments.

The limitation on extern "C" functions still applies, so you would need to use the workaround in the answer I linked.

like image 45
Lia Stratopoulos Avatar answered Sep 30 '22 17:09

Lia Stratopoulos