Dimitar Asenov
Dimitar Asenov

Reputation: 26836

What is the correct way to check whether a template argument is a "true" callable object?

I have the following C++ program:

#include <iostream>
#include <functional>

template<class T> void fun(T t) {
    if (t) std::cout << t();
    else std::cout << "no t";
}

int main() {
    std::function<int ()> f;
    fun(f); //The check will evaluate to false

    fun([](){return "hello";});

    int x = 2;
    fun([x](){return x;}); // Compiler error

    return 0;
}

But it doesn't compile. The problem seems to be that a lambda that captures something is converted to a functor object, which in turn is not convertible to bool and therefore cannot be checked for truthfulness.

What's the right way of writing fun so that I can leave main as it is? Is there a way of doing this while keeping things simple (i.e. not specializing fun)?

EDIT: I really only care about checking whether t is true or not, and I am happy to assume that T is a callable type, without checking that explicitly.

Upvotes: 2

Views: 141

Answers (1)

ecatmur
ecatmur

Reputation: 157344

You're going to need to do some kind of specialization or overloading, but you can at least separate out the work into a predicate function:

template<class T>
typename std::enable_if<
  std::is_constructible<bool, T>::value, bool>::type
okToCall(T&&t) { return static_cast<bool>(t); }
template<class T>
constexpr typename std::enable_if<
  !std::is_constructible<bool, T>::value, bool>::type
okToCall(T&&) { return true; }

template<class T> void fun(T t) {
    if (okToCall(t)) std::cout << t();
    else std::cout << "no t";
}

Example: http://coliru.stacked-crooked.com/a/a08468965ed6d54e

The only real difficulty is working out what to call the okToCall predicate function - what it's really doing is returning true if T is not convertible to bool, but its value converted to bool if it is convertible.

Upvotes: 2

Related Questions