yuan
yuan

Reputation: 2534

what about enhance template enable_if

At first I use the enable_if ,the code I write below will not compile,but it seems right in logic,but won't be support by the enable_if implementation in current.

  1 
  2 #include <iostream>
  3 using namespace std;
  4 
  5 template<int N>
  6 struct S{
  7                 template<class T>
  8                 typename enable_if<N==1,T>::type
  9                 f(T t) {return 1;};
 10 
 11                 template<class T>
 12                 T
 13                 f(T t) {return 0;};
 14 };
 15 
 16 int main() {
 17     S<1> s1;
 18     S<2> s2;
 19     cout << s1.f(99) <<" "<< s2.f(99) << endl;
 20     return 0;
 21 }

The error message are accurate and problems are pointed out precisely.

enable_if.cc19:20: error: call of overloaded ‘f(int)’ is ambiguous
enable_if.cc:9:3: error: no type named ‘type’ in   
                         ‘struct std::enable_if<false, int>’

It seems just the problem of not-well-defined design and can easily be corrected. To deal with it,I can write partial specialized class template:

#include <iostream>
using namespace std;

template<int N> struct S{
        template<class T>
        T
        f(T t) {return 0;};
};
template<> struct S<1>{
        template<class T>
        T
        f(T t) {return 1;};
};
int main() {
    S<1> s1;
    S<2> s2;
    cout << s1.f(99) <<" "<< s2.f(99) << endl;
    return 0;
}

But for the cleanses and convenience, what about to enhance the enable_if template to support such new features urged by the wrong code at first?

Upvotes: 2

Views: 214

Answers (4)

Andy Prowl
Andy Prowl

Reputation: 126562

You could workaround the problem by:

  1. Putting mutually exclusive SFINAE-constraints on your function template;
  2. Forcing the evaluation of the enable_if to be performed at call time.

For instance:

#include <type_traits>

template<int N>
struct S
{
    template <class T>
    typename std::enable_if<N == 1 && std::is_same<T, T>::value, int>::type
    f(T t) {return 1;}

    template <class T>
    typename std::enable_if<N != 1, T>::type
    f(T t) {return 0;}
};

Here is a live example.

Upvotes: 2

Jan Herrmann
Jan Herrmann

Reputation: 2767

std::enable_if is only a tool to choose function overloads. It is implemented as a pure library solution coming from boost. I think the rules for choosing the right overloads are not easy. But asking for changing this in certain cases when enable_if is involved would make it more complicated. So you best work with partial specialisation and disjunctive enable_if.

Upvotes: 0

You can still do it without partial specialisation, but:

  1. You must make sure only one of the functions ever exists (otherwise there's ambiguity)

  2. You must make the enable_if condition depend on the template parameter.

This works:

#include <iostream>
#include <type_traits>
using namespace std;


template <int N>
struct S
{
    template <typename T>
    typename enable_if<(sizeof(T)>0) && N==1, int>::type
    f(T t) { return 1; }

    template <typename T>
    typename enable_if<(sizeof(T)>0) && N!=1, T>::type
    f(T t) { return 0; }
};

int main()
{
    S<1> s1;
    S<2> s2;
    cout << s1.f(99) << " " << s2.f(99) << endl;
}

Live example

Upvotes: 0

Cătălin Pitiș
Cătălin Pitiș

Reputation: 14327

First of all, I suspect you had a typo in your code. Enable if should be paramterized on T, to compile: typename enable_if<N==1,T>::type instead of typename enable_if<N==1,int>::type

Just use the second overload with enable if, too, with inverted condition. It works:

#include <iostream>

using namespace std;

template<int N>
struct S{
                template<class T>
                typename enable_if<N==1,T>::type
                f(T t) {return 1;};

                template<class T>
                typename enable_if<N!=1,T>::type
                f(T t) {return 0;};
};

int main() {
    S<1> s1;
    S<2> s2;
    cout << s1.f(99) <<" "<< s2.f(99) << endl;
    return 0;
}

Upvotes: 1

Related Questions