Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using enable_if on virtual functions

#include <type_traits>

class Base {
public:
    virtual bool f() {
        return true;
    }
};

template<typename T>
class Derived : public Base {
    std::enable_if_t< std::is_copy_constructible<T>::value, bool > f() override {
        return true;
    }

    std::enable_if_t< !std::is_copy_constructible<T>::value, bool > f() override {
        return false;
    }
};

The above code doesn't compile. For some reason I did not manage to understand, the compiler sees the two functions as the same overload before removing one by SFINAE.

What I do not understand, however, is how I am to resolve this problem. The docs I found state I should use templating on the function. That doesn't work, however, because the function is meant to be virtual.

I tried off-loading the problem by calling a non-virtual function, but I cannot get that to compile either:

template<typename T>
class Derived : public Base {
    virtual bool f() override {
        return f_impl();
    }

private:
    template< std::enable_if_t< std::is_copy_constructible<T>::value > = 0 >
    bool f_impl() {
        return true;
    }

    template< std::enable_if_t< !std::is_copy_constructible<T>::value > >
    bool f_impl() {
        return false;
    }
};

int main() {
    Derived<int> a;

    std::cout<<a.f()<<"\n";
}

That fails compilation with:

so.cpp: In instantiation of ‘class Derived<int>’:
so.cpp:29:18:   required from here
so.cpp:18:10: error: ‘std::enable_if<true, void>::type’ {aka ‘void’} is not a valid type for a template non-type parameter

I'm obviously doing something wrong here, but I can't figure out what would be the correct way.

like image 875
Shachar Shemesh Avatar asked Aug 04 '19 09:08

Shachar Shemesh


2 Answers

Unfortunately you can't do that. SFINAE works with templates; e.g. the following code revised from your 2nd sample works.

template< typename X = T>
std::enable_if_t< std::is_copy_constructible<X>::value, bool >
f_impl() {
    return true;
}

template< typename X = T>
std::enable_if_t< !std::is_copy_constructible<X>::value, bool >
f_impl() {
    return false;
}

LIVE

But virtual functions can't be template, that's all.

like image 192
songyuanyao Avatar answered Oct 21 '22 17:10

songyuanyao


Using if constexpr it is possible to branch inside of function at compile time so function can stay virtual:

bool f() override
{
    if constexpr(std::is_copy_constructible<T>::value)
    {
        return true;
    }
    else
    {
        return false;
    }
}
like image 4
user7860670 Avatar answered Oct 21 '22 16:10

user7860670