0
votes

I have a template class that takes a std::function as parameter.

Within the class I need a member function returning bool.

If the cbFunctionT returns bool, the function should return that. If the cbFunctionT returns anything other (or is void), the function should return false.

Expect that I need to use the std::enable_if for that.

Question is how can I check whether cbFunctionT returns bool. In the code below I used the std::is_same as a placeholder for the one I am looking for.

template<typename cbFunctionT> 
class CallBack
{
    template<typename T = cbFunctionT
        typename std::enable_if_t<std::is_same<T,bool>::value>* = nullptr>
    bool funct()
    {
        return cbFunctionT();
    }
    
    template<typename T = cbFunctionT>
    bool funct()
    {
        return false;
    }
}
2
Perhaps specialize the entire template for std::function<bool (Args...)>? - Sam Varshavchik
Do you mean exactly bool? Is const bool acceptable ? bool& ? Something that's implicitly or explicitly convertible to bool ? - MSalters
Did you perhaps mean to say you'd like to call an std::function member of type cbFunctionT, possibly called cbFunction? This code looks like it would return false every time because it tests that cbFunctionT is bool and bool() is false. - parktomatomi

2 Answers

0
votes

I think it's sufficient to write

template<typename T = cbFunctionT>
bool funct()
{
    if constexpr(std::is_same_v<decltype(T()), bool>)
      return T();
    else
      return false;
}
0
votes

My answer takes the liberty of assuming funct is meant to invoke a data member of type cbFunctionT, rather than construct the type itself.

MSalters' general answer (to use if constexpr) is the correct answer if you're able to use C++17 or later. The compiler will evaluate the condition at compile-time and only compile the content inside the selected branch. This enables you to do things inline that you previously had to use std::enable_if for.

But if you're using C++11 or C++14, you can still pull that enable_if out of your class with a generalized helper:

template <bool condition, typename FTrue, typename FFalse, typename... Ts, typename std::enable_if<condition, int>::type = 0>
auto IfConst(FTrue ftrue, FFalse ffalse, Ts&&... ts) -> decltype(ftrue(std::forward<Ts>(ts)...)) {
    return ftrue(std::forward<Ts>(ts)...);
}

template <bool condition, typename FTrue, typename FFalse, typename... Ts, typename std::enable_if<!condition, int>::type = 0>
auto IfConst(FTrue, FFalse ffalse, Ts&&... ts) -> decltype(ffalse(std::forward<Ts>(ts)...)) {
    return ffalse(std::forward<Ts>(ts)...);
}

Then you can implement your goal in a non-template method:

template<typename cbFunctionT> 
class CallBack
{
    cbFunctionT cbFunction;
public:
    CallBack(cbFunctionT cbFunction) : cbFunction(cbFunction) {}
    bool funct() { 
        return IfConst<std::is_same<cbFunctionT, std::function<bool()>>::value>(
            [this]() { return cbFunction && cbFunction(); },
            []() { return false; });
    }
};

Demo: https://godbolt.org/z/o544WM