How do I create an alias for a noexcept function pointer?
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
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.
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.
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);