Question

i have following code that does not compile. This are two functions in a template class that takes the arguments

typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() {
    // ...
}

typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() {
    // ....
}

I want to have a specialization in a member method depending on what type Ret is.

Has anybody some idea?

Was it helpful?

Solution

SFINAE does not work on non-template functions (member or non-member).

As Kerrek SB points out, making them non-member function templates will work. Or as Xeo points out, making them member function templates with a defaulted template argument will also work.

However, this is only working because the two std::enable_if conditions are non-overlapping. If you want to add a different overload for int (say), then you'll find that it doesn't scale as nicely. Depending on what you want to do, tag dispatching generally scales better than SFINAE with multiple alternatives that you want to dispatch on:

#include<type_traits>

template<typename Ret>
class Foo
{
public:
    void _on_dispatched()
    {
        // tag dispachting: create dummy of either std::false_type or std::true_type
        // almost guaranteed to be optimized away by a decent compiler
        helper_on_dispatched(std::is_void<Ret>()); 
    } 

private:
    void helper_on_dispatched(std::false_type)
    {
        // do stuff for non-void
    }

    void helper_on_dispatched(std::true_type)
    {
        // do stuff for void
    }
};

int main()
{
    Foo<void>()._on_dispatched();
    Foo<int>()._on_dispatched();
    return 0;
}

OTHER TIPS

SFINAE only works on templates. Your code can be made to compile with a small modification:

template <typename Ret>
typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ }

template <typename Ret>
typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ }

Usage:

auto q = _on_dispatched<int>();

You can of course not deduce the return type of a function, since it is not deducible. However, you can pack this template inside another template:

template <typename T>
struct Foo
{
    // insert templates here, maybe privately so

    T bar() { return _on_dispatched<T>(); }
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top