Проверьте указатель функции на nullptr в шаблоне для любого вызываемого - PullRequest
1 голос
/ 10 января 2020

Я создал простую оболочку , чтобы ловить, сообщать и перебрасывать исключения (см. Ниже). Он отлично работает для функций, указателей на функции и std::function объектов, но не может скомпилировать лямбды и функторы из-за проверки на nullptr. Есть ли способ исправить это настолько просто, насколько это возможно, чтобы обертку можно было использовать для любого вызываемого? Спасибо!

#include <functional>

template<typename Func, typename TRet, typename... Args>
TRet wrapper(Func func, TRet exit_code_on_error, Args... args) {
    TRet exit_code = exit_code_on_error;
    //if (func) // this condition does not compile for lambdas and functors
    {
        try {
            exit_code = func(std::forward<Args>(args)...);
        } catch(...) {
            // report and possibly rethrow
            //throw;
        }
    }
    return exit_code;
}

int test1(double d) {
    return (int)d;
}

int test2(std::function<int (double)> f, double d) {
    return f(d);
}

struct TestFunctor {
    int operator()(double d) {
        return (int)d;
    }
};

int main() {
    // OK:
    wrapper(test1, 1, 2.3);
    wrapper(&test1, 1, 2.3);
    auto p = test1;
    wrapper(p, 1, 2.3);
    p = nullptr;
    wrapper(p, 1, 2.3);
    wrapper(test2, 1, test1, 2.3);

    // These lines cause the troubles:
    wrapper([](double d){ return (int)d; }, 1, 2.3);
    wrapper(TestFunctor(), 1, 2.3);
}

Ошибка:

wrapper.hpp: error C2451: conditional expression of type 'Func' is illegal
        with
        [
            Func=main::<lambda_1>
        ]

1 Ответ

5 голосов
/ 10 января 2020

Мы можем это исправить, сначала проверив, является ли Func тип указателя, а затем, если это так, проверим, является ли он нулевым указателем. Это будет выглядеть как

template<typename Func, typename TRet, typename... Args>
TRet wrapper(Func func, TRet exit_code_on_error, Args... args) {
    if constexpr(std::is_pointer_v<Func> ||
                 std::is_member_function_pointer_v<Func> ||
                 std::is_same_v<Func, std::function<TRet(Args...)>>) {
        // this will only be compiled if Func is a pointer type or std::function
        if (func == nullptr)
            return exit_code_on_error;
    }
    try {
        return func(std::forward<Args>(args)...);
    } catch(...) {
        // report and rethrow if needed
        //throw;
    }
    return exit_code_on_error;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...