user2296177
user2296177

Reputation: 2837

How can I detect whether a template argument is a noexcept function?

I have function to generate a lambda that acts as a wrapper to a function I can invoke later:

template <typename F, typename... FArgs>
auto make_lambda( F&& f, FArgs&&... f_args )
{
    return [&] () -> std::result_of_t<F( FArgs... )>
    {
        return std::forward<F>( f )( std::forward<FArgs>( f_args )... );
    };
}

I'd like to make the returned lambda noexcept when argument f is noexcept, so my function's return would look like this:

return [&] () noexcept( is_noexcept<decltype( f )>::value )
    -> std::result_of_t<F( FArgs... )>
{
    return std::forward<F>( f )( std::forward<FArgs>( f_args )... );
};

My attempt:

#include <type_traits>

void f() {}
void g() noexcept {}

template <typename F, typename... Args>
struct is_noexcept : std::false_type {};

template <typename F, typename... Args>
struct is_noexcept<F( Args... ) noexcept> : std::true_type {};

int main()
{
    bool constexpr func_test_a{ is_noexcept<decltype( f )>::value }; // true
    bool constexpr func_test_b{ is_noexcept<decltype( g )>::value }; // true
}

However, the test always returns true. What am I missing? Can anyone provide a solution to this problem?

Upvotes: 10

Views: 4257

Answers (2)

user2296177
user2296177

Reputation: 2837

From: http://en.cppreference.com/w/cpp/language/noexcept_spec

The noexcept-specification is not a part of the function type. (until C++17).

Currently, template deduction will not produce the correct results since the noexcept specifier is not part of a function's type; template type deduction will not work until C++17. My way of detecting whether a function is noexcept will be valid in C++17 as will this answer's way.

Upvotes: 13

Jeremy Roman
Jeremy Roman

Reputation: 16355

You can use the noexcept operator, which takes an expression and produces true if that expression is noexcept.

Untested, but this might work for your use case.

return [&] () noexcept(noexcept(std::forward<F>( f )( std::forward<FArgs>( f_args )... )))
    -> std::result_of_t<F( FArgs... )>
{
    return std::forward<F>( f )( std::forward<FArgs>( f_args )... );
};

Upvotes: 12

Related Questions