Reputation: 4850
Supposedly members of a template class shouldn't be instantiated unless they are used.
However this sample seems to instantiate the do_something
member and the enable_if
fails (which would be expected if we'd instantiated it - but AFAIK we did not).
Am I missing something really basic here?
#include <string>
#include <boost/utility.hpp>
struct some_policy {
typedef boost::integral_constant<bool, false> condition;
};
struct other_policy {
typedef boost::integral_constant<bool, true> condition;
};
template <typename policy>
class test {
void do_something(typename boost::enable_if<typename policy::condition>::type* = 0) {}
};
int main() {
test<other_policy> p1;
test<some_policy> p2;
}
Upvotes: 9
Views: 470
Reputation: 217275
SFINAE happens only on template function/method (here, it is your class which is template),
You may do in C++11 (default template parameter for function/method):
template <typename policy>
class test {
template <typename T = policy>
void do_something(typename boost::enable_if<typename T::condition>::type* = 0) {}
};
You may alternatively use specialization, something like
template <bool> struct helper_do_something {};
template <> struct helper_do_something<true>
{
void do_something() { /* Your implementation */ }
};
template <typename policy>
class test : helper_do_something<T::condition::value>
{
// do_something is inherited (and it is present only when T::condition::value is true)
};
Upvotes: 4
Reputation: 55395
Mike Seymour already answered why it doesn't work, here's how to workaround it:
#include <string>
#include <boost/utility.hpp>
struct some_policy {
typedef boost::integral_constant<bool, false> condition;
};
struct other_policy {
typedef boost::integral_constant<bool, true> condition;
};
template <typename policy>
class test {
private:
template<typename P>
void do_something_impl(typename boost::enable_if<typename P::condition>::type* = 0) {}
public:
void do_something()
{
do_something_impl<policy>();
}
};
int main() {
test<other_policy> p1;
test<some_policy> p2;
}
Quick rule of thumb: If you want to do SFINAE, you need a member function template.
Upvotes: 6
Reputation: 254461
From C++11 14.7.1/1:
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions
So the function declaration is instantiated; that fails since it depends on an invalid type.
(Unfortunately, I don't have any historic versions of the standard to hand, but I imagine this rule was similar in C++98)
Upvotes: 8