SFINAE to enable nontemplate member function

好久不见. 提交于 2020-01-01 10:04:04

问题


This is probably a duplicate, but I just can't find one where the OP clearly has the same problem I'm having.
I have a class, and I'm trying to enable operator- only if the class template parameter is not an unsigned type.

#include <type_traits>

template<class T>
struct A {
    typename std::enable_if<!std::is_unsigned<T>::value,A>::type operator-() {return {};}
};

int main() {
    A<unsigned> a=a;
}

Unfortunately, this produces a compiler error any time I instantiate it with an unsigned type as shown.

main.cpp:5:29: error: no type named 'type' in 'std::enable_if<false, A<unsigned int> >'; 'enable_if' cannot be used to disable this declaration
    typename std::enable_if<!std::is_unsigned<T>::value,A>::type operator-() {return {};}
                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:9:17: note: in instantiation of template class 'A<unsigned int>' requested here
    A<unsigned> a=a;
                ^

Well, I can clearly see that enable_if is not going to work here. One vaguely similar question mentioned I can use inheritance and template specialization to work around this, but... is there really no better way?


回答1:


I had the same problem once. Turns out there can't be a substitution failure since the default template argument doesn't depend on a template parameter from the function template. You have to have a template argument defaulted to the enclosing template type, like this:

template<typename U = T,
         class = typename std::enable_if<!std::is_unsigned<U>::value, U>::type>
A operator-() { return {}; }



回答2:


A bit long for a comment: You can also use a free function, even for unary operators.

#include <type_traits>

template<class T>
struct A {
};

template<class T>
typename std::enable_if<!std::is_unsigned<T>::value,A<T>>::type
operator-(A<T>) {return {};}

int main() {
    A<signed> b;
    -b; // ok

    A<unsigned> a;
    -a; // error
}

This doesn't introduce a member function template for each class template.


Here's how you can befriend it:

template<class T>
class A {
    int m;

public:
    A(T p) : m(p) {}

    template<class U>
    friend
    typename std::enable_if<!std::is_unsigned<U>::value,A<U>>::type
    operator-(A<U>);
};

template<class T>
typename std::enable_if<!std::is_unsigned<T>::value,A<T>>::type
operator-(A<T> p) {return {p.m};}

int main() {
    A<signed> b(42);
    -b; // ok

    A<unsigned> a(42);
    //-a; // error
}

You can (should) forward-declare that function template, though.




回答3:


One possible way is introducing a dummy template parameter:

template<class T>
struct A {
    template<
       typename D = int,
       typename = typename std::enable_if<!std::is_unsigned<T>::value, D>::type
    >
    A operator-() {return {};}
};



回答4:


There is a long way using inheritance:

template <class T>
struct A;

template <class T, bool = std::is_unsigned<T>::value>
struct MinusOperator
{
    A<T> operator-()
    {
        A<T>* thisA = static_cast<A<T>*>(this);
        // use thisA instead of this to get access to members of A<T>
    }
};

template <class T>
struct MinusOperator<T, true> {};

template <class T>
struct A : MinusOperator<T>
{
    friend struct MinusOperator<T>;
};


来源:https://stackoverflow.com/questions/22671379/sfinae-to-enable-nontemplate-member-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!