CTMacUser
CTMacUser

Reputation: 2062

Can a function template be made to do default actions upon an inappropriate type instead of an error?

I want to create a function like:

template < typename Other, typename Func, typename T, typename ...Rest >
void  visit( Other &&other, Func &&visitor )
{
    // Wrap "visitor" and "other" with "std::forward" calls
    visitor( make_object<T>(other) );
    visit<Other, Func, Rest...>( other, visitor );
}

The problem is that "Func" may not support all of the types in the list, then the compiler will crap out at the first bad one. I don't want that; I want it to do some default action instead (for my case, do nothing at all).

template < typename Other, typename Func, typename T, typename ...Rest >
void  visit( Other &&other, Func &&visitor )
{
    // Wrap "visitor" and "other" with "std::forward" calls
    if ( Func-can-support-T-either-directly-or-by-converting-it )
        visitor( make_object<T>(other) );
    else
        ;  // might be a throw or a logging instead
    visit<Other, Func, Rest...>( other, visitor );
}

I guess that I can make 2 overloaded auxiliary functions, one taking std::true_type based on the test for compatibility, and the other std::false_type. But how do I create the test?

(Suggestions for a better title and/or additional tags appreciated.)

Upvotes: 2

Views: 105

Answers (1)

Matthieu M.
Matthieu M.

Reputation: 300209

As with all problems in computing, a simple level of indirection is all you need :)

Here is a simple apply function that has a default implementation when things don't work as you wish they did.

template <typename Func>
void apply(Func&& f, ...) { std::cout << "default\n"; }

template <typename Func, typename T>
auto apply(Func&& f, T&& t) -> decltype(f(std::forward<T>(t))) {
    return f(std::forward<T>(t));
}

We can exercise it easily enough:

struct Foo {};
struct Bar {};

struct F {
    void operator()(Foo) { std::cout << "Foo\n"; }
    void operator()(Bar) { std::cout << "Bar\n"; }
};

int main() {
    F f;
    Foo foo;
    Bar bar;
    int i;
    apply(f, foo);
    apply(f, bar);
    apply(f, i);
}

Ideone gives the following output:

Foo
Bar
default

as expected.

Upvotes: 3

Related Questions