1

I am referring to this example SFINAE example,

I have tried to run the sample,

//enable_if
template<bool, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true, T> {
    using type = T;
};

template <typename T>
void do_stuff(typename enable_if<std::is_integral<T>::value, T>::type &t) {
    std::cout<< "Integral selected "<<std::endl;
}

template <typename T>
void do_stuff(typename enable_if<std::is_class<T>::value, T>::type &t) {
    std::cout<<"Class selected " <<std::endl;
}

int main()
{
    int t =25;
    do_stuff(t);
    return 0;
}

But this wont compile, may I know why?

max66
  • 65,235
  • 10
  • 71
  • 111
tesla1060
  • 2,621
  • 6
  • 31
  • 43
  • 2
    Possible duplicate of [Template argument deduction failed, SFINAE](https://stackoverflow.com/questions/37325975/template-argument-deduction-failed-sfinae) – miradulo Apr 07 '18 at 01:53
  • I believe they are related but different issues. – Nicolas Tisserand Apr 07 '18 at 01:59
  • @NicolasTisserand Different issues how? They are identical issues. – miradulo Apr 07 '18 at 02:02
  • OP asked about his own custom `enable_if` implementation. Other questions relates to the standard `enable_if_t` from ``. But the answer ends up being similar, in the end, indeed. – Nicolas Tisserand Apr 07 '18 at 02:08
  • 1
    @NicolasTisserand This is exactly how one would implement `enable_if` - the fact the OP isn't using the `std` version has nothing to do with the problem. – miradulo Apr 07 '18 at 02:13

3 Answers3

3

In addition to the other solutions, if you don't want the enable_if as a return value, you can pass it as a parameter type which is then part of the function signature:

#include <type_traits>
#include <iostream>

//enable_if
template<bool, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true, T> {
    using type = int; // must be a non-type template parameter
};

template <typename T, typename enable_if<std::is_integral<T>::value, T>::type = 0>
void do_stuff(T &t) {
    std::cout<< "Integral selected "<<std::endl;
}

template <typename T, typename enable_if<std::is_class<T>::value, T>::type = 0>
void do_stuff(T &t) {
    std::cout<<"Class selected " <<std::endl;
}

class Foo
{
  public:
    Foo() = default;
};

int main()
{
    int t =25;
    Foo f;
    do_stuff(t);
    do_stuff(f);
    return 0;
}
Samaursa
  • 16,527
  • 21
  • 89
  • 160
1

This works for me:

template <typename T>
typename enable_if<std::is_integral<T>::value, void>::type
do_stuff(T& t) {
    std::cout<< "Integral selected "<<std::endl;
}

template <typename T>
typename enable_if<std::is_class<T>::value, void>::type
do_stuff(T& t) {
    std::cout<<"Class selected " <<std::endl;
}

The problem was that the enable_if static calls were applied to the function parameters instead of the return types.

0

But this wont compile, may I know why?

Because, calling do_stuff() the type T can't be deduced through enable_if.

But works if you call do_stuff() explicating the type T

int t =25;
do_stuff<int>(t); // compile

To avoid this problem, I suggest you the solution proposed by Nicolas Tisserand (+1) (there is no need to explicate void as second parameter of enable_if because is the default)

template <typename T>
typename enable_if<std::is_integral<T>::value>::type
do_stuff(T& t) {
    std::cout<< "Integral selected "<<std::endl;
}

template <typename T>
typename enable_if<std::is_class<T>::value>::type
do_stuff(T& t) {
    std::cout<<"Class selected " <<std::endl;
}

with SFINAE enabled through return type.

This way the type T is deducible from the argument, so you doesn't need to explicate it.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
max66
  • 65,235
  • 10
  • 71
  • 111