EN VI

C++ - How to conditionally declare a member overload on class templates?

2024-03-16 07:00:05
C++ - How to conditionally declare a member overload on class templates?

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?

Solution:

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 >
//                                                        ^
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login