2

For example I have type:

typedef DWORD WINAPI HANDLER_FUNCTION_EX (DWORD);

And I want:

static as_noexcept<HANDLER_FUNCTION_EX>::type my_func; // forward declaration
static_assert(noexcept(my_func(0)));

I got something like:

template<typename>
struct noexcept_trait;

// specialization to infer signature
template<typename Result, typename... Args>
struct noexcept_trait<Result(Args...)>
{
    using as_noexcept = Result(Args...) noexcept;
    using as_throwing = Result(Args...);
};
// since C++17 noexcept-specification is a part of the function type
// so first specialization won't match
template<typename Result, typename... Args>
struct noexcept_trait<Result(Args...) noexcept>
{
    using as_noexcept = Result(Args...) noexcept;
    using as_throwing = Result(Args...);
};

template<typename T>
using add_noexcept_t = typename noexcept_trait<T>::as_noexcept;
template<typename T>
using remove_noexcept_t = typename noexcept_trait<T>::as_throwing;

But this code creates totally new type and drops all additional info (calling convention, attributes e.g. [[deprecated]]). So it's not safe. How can I fix it?

OwnageIsMagic
  • 1,949
  • 1
  • 16
  • 31
  • Are you sure `HANDLER_FUNCTION_EX()` isn't throwing? Even if it is a pure C function, if it might call another function indirectly, that other function might throw. See [this question](https://stackoverflow.com/questions/24362616/does-the-c-standard-mandate-that-c-linkage-functions-are-noexcept) for an interesting read. – G. Sliepen Sep 27 '21 at 18:15
  • 1
    @G.Sliepen `HANDLER_FUNCTION_EX` is just function type name. Actual function is `my_func` and defined with `noexcept`, so I'm sure it won't throw. – OwnageIsMagic Sep 27 '21 at 18:53
  • If your compiler extends the type system to have calling convention modifiers, can’t you add more specializations to handle those cases? It’s painfully long, to be sure, but it’s not difficult. – Davis Herring Sep 27 '21 at 19:02
  • @DavisHerring `__attribute__((stdcall))` or `__stdcall` is not part of function type, so all specializations are conflicting (error: class template has already been defined) – OwnageIsMagic Sep 27 '21 at 19:14
  • 1
    @DavisHerring it was failing because in x64 mode msvc treats __cdecl same as __stdcall. if I choose x86 target, they are treated as different types. https://devblogs.microsoft.com/oldnewthing/20200717-00/?p=103989 – OwnageIsMagic Sep 27 '21 at 21:35

1 Answers1

0

Add

template<typename Result, typename... Args>
struct noexcept_trait<Result __stdcall(Args...)>
{
    using as_noexcept = Result __stdcall(Args...) noexcept;
    using as_throwing = Result __stdcall(Args...);
};

and similar elsewhere. But you should only do this if !is_same_v< void(*)(), void(__stdcall *)() >. If __stdcall does nothing on your platform, you'll get a conflict here.

Attributes are explicitly not part of the type system. [[deprecated]] applies to the type definition itself, not the thing being defined. The very use of that type to create the alias is [[deprecated]].

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524