Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ remove noexcept from decltype returned type

#include <functional>
#include <sys/types.h>
#include <sys/socket.h>


std::function<decltype(::bind)> mockbind = ::bind;

int main()
{
}

The code above works on most of the platforms I compile on. But on ubuntu 14.04 using g++-7 I get an error:

X.cpp:7:65: error: variable ‘std::function<int(int, const sockaddr*, unsigned int) noexcept> mockbind’ has initializer but incomplete type
 std::function<int(int, const sockaddr*, unsigned int) noexcept> mockbind = ::bind;
                                                                 ^~~~~~~~

Now if I manually go and change the type of mockbind

std::function<int(int, const sockaddr*, unsigned int) noexcept> mockbind = ::bind;

As expected I get the same error:
Now if I remove the noexcept

std::function<int(int, const sockaddr*, unsigned int)> mockbind = ::bind;

It compiles as expected.

So the question is can I apply some template code to remove the noexcept from the type returned by decltype and make it work as expected.

like image 584
Martin York Avatar asked Aug 30 '17 16:08

Martin York


People also ask

What is the return type of decltype?

If the expression parameter is a call to a function or an overloaded operator function, decltype(expression) is the return type of the function. Parentheses around an overloaded operator are ignored. If the expression parameter is an rvalue, decltype(expression) is the type of expression .

What does decltype in c++?

In the C++ programming language, decltype is a keyword used to query the type of an expression. Introduced in C++11, its primary intended use is in generic programming, where it is often difficult, or even impossible, to express types that depend on template parameters.


2 Answers

A simple class specialization trick should work:

template <typename T> struct remove_noexcept
{
    using type = T;
};
template <typename R, typename ...P> struct remove_noexcept<R(P...) noexcept>
{
    using type = R(P...);
};
template <typename T> using remove_noexcept_t = typename remove_noexcept<T>::type;

// ...

std::function<remove_noexcept_t<decltype(::bind)>> mockbind = ::bind;

You could somewhat easily extend it to remove noexcept from [member] function pointers, that's left as an excercise to the reader.

Also you could comment out using type = T; if you wish to get a compile-time error if there is no noexcept instead of leaving the type unchanged.

like image 191
HolyBlackCat Avatar answered Nov 15 '22 22:11

HolyBlackCat


While HolyBlackCat's answer covers the majority of actual use cases, it would fail to cover many possible cases, including a qualified function type (e.g., int(int) const noexcept), a variadic templated variadic function (e.g., template<typename... Ts> void foo(Ts..., ...) noexcept), and pointer to member functions (which don't operate under normal pointer rules at all, e.g., int(foo::*)(int) noexcept).

Implementing a remove_noexcept trait that covers all of these edge cases is no small undertaking, but here's my take on it. I implemented remove_noexcept_t in terms of make_noexcept_t<T, bool>, whose second parameter allows you to toggle the resultant noexcept state (noexcept(true) or noexcept(false), as you'd expect).

Notably, this does work with pointer to member functions, but does not work with function pointers. This is by design (primarily following the logic of std::is_pointer), though you could fairly easily set up a using declaration like add_pointer_t<make_noexcept_t<remove_pointer_t<decay_t<T>>>>.

Live Demo (UPDATED)

EDIT: The below implementation was not tested for accuracy with MSVC++ 2019 (v142) before I posted this. While it does work with GCC and Clang, this implementation does NOT work with MSVC++ 2019 (v142). The live demo link has been updated to a much longer implementation (twice as many specializations), which is too long to post to StackOverflow. That implementation has been tested with GCC, Clang, and MSVC++ 2019 (v142).

template<typename T, bool noexcept_state = true>
struct make_noexcept { using type = T; };

template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) noexcept, noexcept_state> { using type = R(Args...) noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const noexcept, noexcept_state> { using type = R(Args...) const noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) volatile noexcept, noexcept_state> { using type = R(Args...) volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const volatile noexcept, noexcept_state> { using type = R(Args...) const volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) noexcept, noexcept_state> { using type = R(Args..., ...) noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const noexcept, noexcept_state> { using type = R(Args..., ...) const noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) volatile noexcept, noexcept_state> { using type = R(Args..., ...) volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const volatile noexcept, noexcept_state> { using type = R(Args..., ...) const volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) & noexcept, noexcept_state> { using type = R(Args...) & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const & noexcept, noexcept_state> { using type = R(Args...) const & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) volatile & noexcept, noexcept_state> { using type = R(Args...) volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const volatile & noexcept, noexcept_state> { using type = R(Args...) const volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) & noexcept, noexcept_state> { using type = R(Args..., ...) & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const & noexcept, noexcept_state> { using type = R(Args..., ...) const & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) volatile & noexcept, noexcept_state> { using type = R(Args..., ...) volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const volatile & noexcept, noexcept_state> { using type = R(Args..., ...) const volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) && noexcept, noexcept_state> { using type = R(Args...) && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const && noexcept, noexcept_state> { using type = R(Args...) const && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) volatile && noexcept, noexcept_state> { using type = R(Args...) volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const volatile && noexcept, noexcept_state> { using type = R(Args...) const volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) && noexcept, noexcept_state> { using type = R(Args..., ...) && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const && noexcept, noexcept_state> { using type = R(Args..., ...) const && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) volatile && noexcept, noexcept_state> { using type = R(Args..., ...) volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const volatile && noexcept, noexcept_state> { using type = R(Args..., ...) const volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) noexcept, noexcept_state> { using type = R(C::*)(Args...) noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const noexcept, noexcept_state> { using type = R(C::*)(Args...) const noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) volatile noexcept, noexcept_state> { using type = R(C::*)(Args...) volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const volatile noexcept, noexcept_state> { using type = R(C::*)(Args...) const volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) noexcept, noexcept_state> { using type = R(C::*)(Args..., ...) noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const noexcept, noexcept_state> { using type = R(C::*)(Args...) const noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) volatile noexcept, noexcept_state> { using type = R(C::*)(Args...) volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const volatile noexcept, noexcept_state> { using type = R(C::*)(Args...) const volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) & noexcept, noexcept_state> { using type = R(C::*)(Args...) & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const & noexcept, noexcept_state> { using type = R(C::*)(Args...) const & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) volatile & noexcept, noexcept_state> { using type = R(C::*)(Args...) volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const volatile & noexcept, noexcept_state> { using type = R(C::*)(Args...) const volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) & noexcept, noexcept_state> { using type = R(C::*)(Args..., ...) & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const & noexcept, noexcept_state> { using type = R(C::*)(Args..., ...) const & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) volatile & noexcept, noexcept_state> { using type = R(C::*)(Args..., ...) volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const volatile & noexcept, noexcept_state> { using type = R(C::*)(Args..., ...) const volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) && noexcept, noexcept_state> { using type = R(C::*)(Args...) && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const && noexcept, noexcept_state> { using type = R(C::*)(Args...) const && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) volatile && noexcept, noexcept_state> { using type = R(C::*)(Args...) volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const volatile && noexcept, noexcept_state> { using type = R(C::*)(Args...) const volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) && noexcept, noexcept_state> { using type = R(C::*)(Args..., ...) && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const && noexcept, noexcept_state> { using type = R(C::*)(Args..., ...) const && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) volatile && noexcept, noexcept_state> { using type = R(C::*)(Args..., ...) volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const volatile && noexcept, noexcept_state> { using type = R(C::*)(Args..., ...) const volatile && noexcept(noexcept_state); };

// MSVC++ 2019 (v142) doesn't allow `noexcept(x)` with a template parameter `x` in the template specialization list.
// (e.g., `struct make_noexcept<R(Args...) noexcept(noexcept_state)>` gives - C2057: expected constant expression)
// GCC 7.1.0 and Clang 5.0.0 (and later versions) were tested and do allow this, so MSVC++ is probably wrong.
// $ g++ prog.cc -Wall -Wextra -std=c++17 -pedantic
// $ clang++ prog.cc -Wall -Wextra -std=c++17 -pedantic

template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...), noexcept_state> { using type = R(Args...) noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const, noexcept_state> { using type = R(Args...) const noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) volatile, noexcept_state> { using type = R(Args...) volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const volatile, noexcept_state> { using type = R(Args...) const volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...), noexcept_state> { using type = R(Args..., ...) noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const, noexcept_state> { using type = R(Args..., ...) const noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) volatile, noexcept_state> { using type = R(Args..., ...) volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const volatile, noexcept_state> { using type = R(Args..., ...) const volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...)&, noexcept_state> { using type = R(Args...) & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const &, noexcept_state> { using type = R(Args...) const & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) volatile &, noexcept_state> { using type = R(Args...) volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const volatile &, noexcept_state> { using type = R(Args...) const volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...)&, noexcept_state> { using type = R(Args..., ...) & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const &, noexcept_state> { using type = R(Args..., ...) const & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) volatile &, noexcept_state> { using type = R(Args..., ...) volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const volatile &, noexcept_state> { using type = R(Args..., ...) const volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) &&, noexcept_state> { using type = R(Args...) && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const &&, noexcept_state> { using type = R(Args...) const && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) volatile &&, noexcept_state> { using type = R(Args...) volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args...) const volatile &&, noexcept_state> { using type = R(Args...) const volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) &&, noexcept_state> { using type = R(Args..., ...) && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const &&, noexcept_state> { using type = R(Args..., ...) const && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) volatile &&, noexcept_state> { using type = R(Args..., ...) volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename... Args>
struct make_noexcept<R(Args..., ...) const volatile &&, noexcept_state> { using type = R(Args..., ...) const volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...), noexcept_state> { using type = R(C::*)(Args...) noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const, noexcept_state> { using type = R(C::*)(Args...) const noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) volatile, noexcept_state> { using type = R(C::*)(Args...) volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const volatile, noexcept_state> { using type = R(C::*)(Args...) const volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...), noexcept_state> { using type = R(C::*)(Args..., ...) noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const, noexcept_state> { using type = R(C::*)(Args...) const noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) volatile, noexcept_state> { using type = R(C::*)(Args...) volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const volatile, noexcept_state> { using type = R(C::*)(Args...) const volatile noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...)&, noexcept_state> { using type = R(C::*)(Args...) & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const &, noexcept_state> { using type = R(C::*)(Args...) const & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) volatile &, noexcept_state> { using type = R(C::*)(Args...) volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const volatile &, noexcept_state> { using type = R(C::*)(Args...) const volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...)&, noexcept_state> { using type = R(C::*)(Args..., ...) & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const &, noexcept_state> { using type = R(C::*)(Args..., ...) const & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) volatile &, noexcept_state> { using type = R(C::*)(Args..., ...) volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const volatile &, noexcept_state> { using type = R(C::*)(Args..., ...) const volatile & noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) &&, noexcept_state> { using type = R(C::*)(Args...) && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const &&, noexcept_state> { using type = R(C::*)(Args...) const && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) volatile &&, noexcept_state> { using type = R(C::*)(Args...) volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args...) const volatile &&, noexcept_state> { using type = R(C::*)(Args...) const volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) &&, noexcept_state> { using type = R(C::*)(Args..., ...) && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const &&, noexcept_state> { using type = R(C::*)(Args..., ...) const && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) volatile &&, noexcept_state> { using type = R(C::*)(Args..., ...) volatile && noexcept(noexcept_state); };
template<bool noexcept_state, typename R, typename C, typename... Args>
struct make_noexcept<R(C::*)(Args..., ...) const volatile &&, noexcept_state> { using type = R(C::*)(Args..., ...) const volatile && noexcept(noexcept_state); };

template<typename T, bool noexcept_state = true>
using make_noexcept_t = typename make_noexcept<T, noexcept_state>::type;

template<typename T>
using remove_noexcept_t = make_noexcept_t<T, false>;
like image 23
monkey0506 Avatar answered Nov 15 '22 20:11

monkey0506