Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting operator +

I am trying to detect the operator plus on a class with the following code which is not working with sfinae any experts have any ideas on what I am missing.

Also the complier dies when you remove the operator + on the type you are trying to detect it on

    template<class T1, class T2>
        class has_addition_operator
        {
        private:

            typedef char no;

            static auto has(T1* a, T2* b) -> decltype( *a + *b);

            static char has(...);

        public:
            enum{
                value = (sizeof( has(new T1(), new T2())) != sizeof(no))
            };

        };


struct point{
        int x, y;

        point operator + (point const & o){

            point r = *this;
            r.x += o.x;
            r.y += o.y;
            return r;

        }

    };

    bool has = liboperator::has_addition_operator<point,point>::value;

The compiler has the following output:

1>------ Build started: Project: liboperator, Configuration: Debug Win32 ------
1>  liboperator.cpp
1>c:\projects\liboperator\liboperator\liboperator\has_addition_operator.h(15): error C2784: 'std::_String_iterator<_Mystr> std::operator +(_String_iterator<_Mystr>::difference_type,std::_String_iterator<_Mystr>)' : could not deduce template argument for 'std::_String_iterator<_Mystr>' from 'point'
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstring(420) : see declaration of 'std::operator +'
1>          c:\projects\liboperator\liboperator\liboperator\liboperator.cpp(26) : see reference to class template instantiation 'liboperator::has_addition_operator<T1,T2>' being compiled
1>          with
1>          [
1>              T1=point,
1>              T2=point
1>          ]
1>c:\projects\liboperator\liboperator\liboperator\has_addition_operator.h(15): error C2784: 'std::_String_const_iterator<_Mystr> std::operator +(_String_const_iterator<_Mystr>::difference_type,std::_String_const_iterator<_Mystr>)' : could not deduce template argument for 'std::_String_const_iterator<_Mystr>' from 'point'
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstring(288) : see declaration of 'std::operator +'
1>c:\projects\liboperator\liboperator\liboperator\has_addition_operator.h(15): error C2784: 'std::move_iterator<_RanIt> std::operator +(_Diff,const std::move_iterator<_RanIt> &)' : could not deduce template argument for 'const std::move_iterator<_RanIt> &' from 'point'
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(1947) : see declaration of 'std::operator +'
1>c:\projects\liboperator\liboperator\liboperator\has_addition_operator.h(15): error C2784: 'std::_Array_iterator<_Ty,_Size> std::operator +(_Array_iterator<_Ty,_Size>::difference_type,std::_Array_iterator<_Ty,_Size>)' : could not deduce template argument for 'std::_Array_iterator<_Ty,_Size>' from 'point'
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(1801) : see declaration of 'std::operator +'
1>c:\projects\liboperator\liboperator\liboperator\has_addition_operator.h(15): error C2784: 'std::_Array_const_iterator<_Ty,_Size> std::operator +(_Array_const_iterator<_Ty,_Size>::difference_type,std::_Array_const_iterator<_Ty,_Size>)' : could not deduce template argument for 'std::_Array_const_iterator<_Ty,_Size>' from 'point'
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(1662) : see declaration of 'std::operator +'
1>c:\projects\liboperator\liboperator\liboperator\has_addition_operator.h(15): error C2784: 'std::reverse_iterator<_RanIt> std::operator +(_Diff,const std::reverse_iterator<_RanIt> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'point'
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(1226) : see declaration of 'std::operator +'
1>c:\projects\liboperator\liboperator\liboperator\has_addition_operator.h(15): error C2784: 'std::_Revranit<_RanIt,_Base> std::operator +(_Diff,const std::_Revranit<_RanIt,_Base> &)' : could not deduce template argument for 'const std::_Revranit<_RanIt,_Base> &' from 'point'
1>          c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility(1031) : see declaration of 'std::operator +'
1>c:\projects\liboperator\liboperator\liboperator\has_addition_operator.h(15): error C2676: binary '+' : 'point' does not define this operator or a conversion to a type acceptable to the predefined operator
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
like image 274
Blair Davidson Avatar asked Dec 26 '22 02:12

Blair Davidson


2 Answers

SFINAE stands for "Substitution failure is not an error". Note the bolded part - there's nothing to substitute in your checker function

static auto has(T1* a, T2* b) -> decltype( *a + *b);

because it's not a template itself. When you instantiate the trait class, its signature is already known and whatever type it was instantiated with it's supposed to have operator+.

You need to make has a template itself. Something like this should work (untested):

template<typename U1, typename U2>
static constexpr auto has(int*)
    -> decltype( std::declval<U1>() + std::declval<U2>(), yes() )

Where yes is a typedef for a type with different size than sizeof(no). The way the above is written, there's no chance for compiler to deduce U1 and U2 so you need to specify them explicitly. Therefore, you'll need to make the fallback function a template, too.

like image 118
jrok Avatar answered Jan 10 '23 02:01

jrok


The problem is with the "has operator" case:

static auto has(T1* a, T2* b) -> decltype( *a + *b);

You are telling the compiler that there is always an overload of has that accepts a T1* and a T2* and returns... the type of the expression T1 + T2. But this expression has a type only if an addition operator is available.

This gets you into a loop: in order to determine if an operator+ exists (to populate value) the compiler has to determine the return type of operator+... which might not exist!

like image 42
Jon Avatar answered Jan 10 '23 03:01

Jon