简体   繁体   中英

How to define different member function with enable_if?

My code is:

template<int s>
struct C{
    typename std::enable_if<s == 1, int>::type
    fun(){std::cout<<"fun1";}
    typename std::enable_if<s == 2, int>::type
    fun(){std::cout<<"fun2";}
};

int main() {
    C<1> c;
    c.fun();
}

The compiler said:

error: functions that differ only in their return type cannot be overloaded

my compiler is g++ 4.1.2 if use template<int t = s> before function, it will warn that is C++11 feature. I want to know how to solve that without using C++11?

If you are able to implement the enable_if trait, you can rearrange your code as it follows (minimal, complete example) to have it working:

#include<type_traits>
#include<iostream>

struct C {
    template<int s>
    typename std::enable_if<s == 1, int>::type
    fun() { std::cout<<"fun1"; }

    template<int s>
    typename std::enable_if<s == 2, int>::type
    fun() { std::cout<<"fun2"; }
};

int main() {
    C c;
    c.fun<1>();
}

Your version (almost identical to the following one) won't work even using C++11 features, because it is not a SFINAE resolution of the name fun :

#include<type_traits>
#include<iostream>

template<int s>
struct C {
    typename std::enable_if<s == 1, int>::type
    fun() { std::cout<<"fun1"; }
    typename std::enable_if<s == 2, int>::type
    fun() { std::cout<<"fun2"; }
};

int main() {
    C<1> c;
    c.fun();
}

If you want the class to be instantiated like C<1> , simply SFINAE isn't the way to go this time.
Please, note that s is known at compile time where you decide to use the template class, so you can use it whenever you want.
It follows a possible solution:

#include<type_traits>
#include<iostream>

template<int s>
struct C {
    void fun() {
        if(s == 1) {
            std::cout<<"fun1";
        } else if(s == 2) {
            std::cout<<"fun2";
        }
    }
};

int main() {
    C<1> c;
    c.fun();
}

Another solution would be possible using partial specialization, like the following one:

#include<type_traits>
#include<iostream>

template<int s>
struct C;

template<>
struct C<1> {
    void fun() { std::cout<<"fun1"; }
};

template<>
struct C<2> {
    void fun() { std::cout<<"fun2"; }
};

int main() {
    C<1> c;
    c.fun();
}

Which one is the right one for you mainly depends on the actual problem, so I cannot say, but at least now you have several solutions from which to choice.

Even if I wouldn't suggest this approach, it follows another possible solution.
I add it as a separate answer only for the sake of curiosity, because I find the other answer most suitable.
Anyway, this one can be of interest because it shows how to use sfinae and function resolution to solve such an issue.

#include<iostream>
#include<type_traits>

template<int s>
struct C {
    template<int i>
    typename std::enable_if<i == 1>::type
    fun(){std::cout<<"fun1"<<std::endl;}

    template<int i>
    typename std::enable_if<i == 2>::type
    fun(){std::cout<<"fun2"<<std::endl;}

    void fun() {
        fun<s>();
    }
};

int main() {
    C<1> c1;
    c1.fun();
    C<2> c2;
    c2.fun();
}

If you are unable to implement std::enable_if as mentioned in the comments, I have an alternative shown below. The solution relies on the compiler to optimize out the switch statement, however will still work with a non-optimizing compiler.

#include <iostream>

template <int s>
struct C {
  int fun() {
    switch (s) {
      case 1:
        fun1();
        break;
      case 2:
        fun2();
        break;
      default:
        assert(0);
    }
  }

  inline int fun1() { std::cout << "fun1"; }
  inline int fun2() { std::cout << "fun2"; }
};

Edit: I had a look through the source code for #include <type_traits> and found the template for std::enable_if this is shown below. GPL license applies. From g++ source code, not my own work. I would recommend combining this with skypjacks answer and you most likely solve your problem.

// Primary template.
/// Define a member typedef @c type only if a boolean constant is true.
template<bool, typename _Tp = void>
  struct enable_if 
  { };

// Partial specialization for true.
template<typename _Tp>
  struct enable_if<true, _Tp>
  { typedef _Tp type; };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM