I'm trying to employ std::enable_if
to conditionally define a member overload on a class template, according to the template argument:
#include <cstddef>
#include <memory>
#include <math.h>
#include <iostream>
#include <type_traits>
//------------------------------------------------------------------------------
class MyDouble {
public:
MyDouble(double value_) : value(value_) { /* ... */ };
operator double() const { return value; };
protected:
double value;
};
//------------------------------------------------------------------------------
class Base {
public:
explicit Base(double v1_ = 0.0, double v2_ = 0.0, double v3_ = 0.0);
virtual ~Base() = default;
virtual void update(double d1, double d2, double d3);
double v1;
double v2;
double v3;
};
Base::Base(double v1_, double v2_, double v3_) :
v1(v1_), v2(v2_), v3(v3_) {
/* ... */
}
void Base::update(double d1, double d2, double d3) {
v1 += d1;
v2 += d2;
v3 += d3;
}
//------------------------------------------------------------------------------
template < typename Arg = double >
class Derived : public Base {
public:
explicit Derived(Arg extra_);
virtual ~Derived() = default;
void update(double d1, double d2, double d3) override;
// overload, declared only when Arg == MyDouble
template < typename T = Arg, typename = typename std::enable_if< std::is_same< Arg, MyDouble >::value >::type >
void update(double d1, double d2, double d3, double extra);
Arg extra;
};
template < typename Arg >
Derived< Arg >::Derived(Arg extra_) :
Base(0.0, 0.0, 0.0),
extra(extra_) {
/* ... */
}
template < typename Arg >
void Derived< Arg >::update(double d1, double d2, double d3) {
std::cout << "update" << std::endl;
Base::update(d1, d2, d3);
}
template < typename Arg >
template < typename T, typename >
void Derived< Arg >::update(double d1, double d2, double d3, double extra) {
std::cout << "MyDouble update" << std::endl;
// ...
Base::update(d1, d2, d3);
}
//------------------------------------------------------------------------------
int main(int argc, char const *argv[]) {
Derived< double > foo(5);
Derived< MyDouble > bar(10);
return 0;
}
However, I get
In instantiation of ‘class Derived<double>’:
[...]
error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
which tells me, at the very least, that the condition is being checked. What is the proper SFINAE syntax to achieve the desired behavior?
Your enable_if
does not depend on the template argument of the function, which is T
. There is no substitution, and thus no substitution failure.
Change to:
template <typename T = Arg,
typename = typename std::enable_if<std::is_same<T, MyDouble >::value >::type >
// ^