.
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
struct MyClass{
void hello( void) {
hello(std::is_same<T,bool>());
}
void hello(std::true_type){
cout<<"hello only for bools"<<endl;
}
};
int main(int argc, char** argv){
MyClass<bool> myclass1;
myclass1.hello();
MyClass<float> myclass2;
//myclass2.hello(); //throws error as it should
return 0;
}
I wrote the above code after reading enable_if method specialization. I want the hello() method to exist only if template argument is bool and it works. However I am running into problems when I am trying to solve the same problem using enable_if. I have the following code. Any help is appreciated. If enable_if is not appropriate for this job, what is generally used?
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
struct MyClass{
typename std::enable_if<std::is_same<T,bool>::value, void>::type
hello(void)
{
cout<<"hello only for bools"<<endl;
}
};
int main(int argc, char** argv){
MyClass<bool> myclass1;
myclass1.hello();
MyClass<float> myclass2;// compilation error. Don't know how to solve
//myclass2.hello(); //I want only this line to cause compilation error
return 0;
}
EDIT: I found the solution to my question in jpihl's answer at std::enable_if to conditionally compile a member function. But could anyone explain why the above doesn't work?
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
struct MyClass{
template<class Q = T>
typename std::enable_if<std::is_same<Q, bool>::value, void>::type hello()
{
cout<<"hello only for bools"<<endl;
}
};
int main(int argc, char** argv){
MyClass<bool> myclass1;
myclass1.hello();
MyClass<float> myclass2;// throws errow. Don't know how to solve
myclass2.hello(); //
return 0;
}
Your first attempt with
enable_if
does not work because SFINAE applies in overload resolution of function (or member function) templates, where it will eliminate a specialization of the function template from the overload set when that specialization cannot compile.The member
hello
, in your first attempt, is not a member function template. It has no template parameters. It is simply a member function of a class template.Its return type is formulated by an
enable_if
expression that will provoke compilation failure if the class template parameterT
is not instantiated asbool
. This doesn't make the member function itself into a template. SFINAE has no application. Once you declareMyClass<float> myclass2
, the specialization ofMyClass<T>
and all its members is completely determined. The member functionhello
of that specialization must be instantiated, and withT
=float
the attempt to do so must fail to compile.In the second, successful attempt,
hello
is a member function template (of a class template). It has a template parameter,Q
, which by default is =T
. So SFINAE applies and you can leverage it withenable_if
in the intended manner. You may declareMyClass<float> myclass2
without error, because doing so does not force any instantiation of the template memberMyClass<float>::hello<Q>
Since you have written only one overload of
hello
, there is only one specialization of the member function template for any choice ofQ
. WhenQ
=bool
, that single specialization survives andmyclass1.hello()
will compile. WhenQ
!=bool
, SFINAE eliminates the that single specialization andmyclass2.hello()
does not compile.To appeciate vividly how SFINAE in the second case is operating at instantation of the member function template, consider that:
is fine; while on the other hand:
does not compile.
Here is documentation of SFINAE