【问题标题】:Detecting operator +检测算子 +
【发布时间】:2013-06-13 08:46:52
【问题描述】:

我正在尝试使用以下代码在一个类上检测运算符,该代码不适用于 sfinae,任何专家都对我所缺少的有任何想法。

当您在尝试检测它的类型上删除运算符 + 时,编译器也会死亡

    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;

编译器有以下输出:

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 ==========

【问题讨论】:

  • 更具体一点 - 您遇到了什么错误,您使用的是什么编译器以及“编译器死掉”是什么意思?
  • Ok 将粘贴输出
  • 不确定是否有帮助。
  • 如果 T1+T2 产生与 char 相同大小的类型,这种方法不会失败吗?
  • 可能。但我想在为此添加完整的专业化之前让它工作。

标签: c++ templates c++11 sfinae


【解决方案1】:

SFINAE 代表“替换失败不是错误”。请注意粗体部分 - 在您的检查器功能中没有什么可以替代的

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

因为它本身不是模板。当您实例化 trait 类时,它的签名是已知的,并且它被实例化的任何类型都应该具有 operator+

您需要将has 本身设为模板。像这样的东西应该可以工作(未经测试):

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

其中yes 是与sizeof(no) 大小不同的类型的typedef。上面的写法,编译器没有机会推导出U1U2,所以你需要明确地指定它们。因此,您还需要将回退函数设为模板。

【讨论】:

  • 完全正确我错过了作为模板的功能,因此 SFINAE 从未应用。谢谢。
  • @BlairDavidson 我也是,事实上,哈哈。编辑。
  • 嗨,您还帮助我在 github.com/loosechainsaw/liboperator 上为我的项目 liboperator 获得了第一次提交
【解决方案2】:

问题在于“有运算符”的情况:

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

您告诉编译器总是有一个has 的重载,它接受T1*T2* 并返回...表达式T1 + T2 的类型。但是这个表达式只有在加法运算符可用时才有类型。

这会让你进入一个循环:为了确定operator+ 是否存在(填充value),编译器必须确定operator+ 的返回类型...这可能不存在!

【讨论】:

  • 谢谢伙计。会有戏
  • @BlairDavidson:坦率地说,我不确定这是否可能。
猜你喜欢
  • 2011-02-09
  • 2010-11-20
  • 1970-01-01
  • 2014-10-17
  • 2018-12-26
  • 2011-09-17
  • 2012-02-21
  • 2011-05-19
  • 2014-01-31
相关资源
最近更新 更多