为什么过载运算符&&错误?

时间:2014-04-23 12:04:20

标签: c++ templates gcc c++11

我尝试编写表达式模板。

   template<typename Tag>
struct Expr{
    tuple<Tag> value;
};
struct logic_and{};

template<typename T>
struct isExpr{enum{value=0};};
template<typename Tag>
struct isExpr<Expr<Tag>>{enum{value=1};};

template<typename L,typename R,typename=std::enable_if<isExpr<L>::value||isExpr<R>::value> >
Expr<logic_and> operator&&(const L&,const R&)
{
   return {};
}

但mingw gcc 4.8.1错误:

...include\c++\ext\string_conversions.h||In instantiation of '_Ret __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long long unsigned int]':|
...include\c++\bits\basic_string.h|2825|required from here|
...include\c++\ext\string_conversions.h|67|error: no match for 'operator||' (operand types are 'bool' and 'Expr<logic_and>')|
...include\c++\ext\string_conversions.h|67|note: candidate is:|
...include\c++\ext\string_conversions.h|67|note: operator||(bool, bool) <built-in>|
...include\c++\ext\string_conversions.h|67|note:   no known conversion for argument 2 from 'Expr<logic_and>' to 'bool'|
...include\c++\ext\string_conversions.h||In instantiation of '_Ret __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long long unsigned int]':|

看起来找到一个bool结果......如果我替换为

template<typename L,typename R,typename=std::enable_if<isExpr<L>::value||isExpr<R>::value> >
Expr<logic_and> operator||(const L&,const R&)
{
   return {};
}

或替换为

template<typename L,typename R,typename=std::enable_if<isExpr<L>::value||isExpr<R>::value> >
bool operator&&(const L&,const R&)
{
   return {};
}
全部通过!是gcc bug?我该如何解决?

编辑抱歉我误导了enable_if ....现在我重现了这个错误:

#include <type_traits>
#include <memory>
namespace TestFoo{
struct Tag {};
struct shift_left:Tag {};
struct shift_right:Tag {};
struct multiplies:Tag {};
struct divides:Tag {};
struct modulus:Tag {};
struct plus:Tag {};
struct minus:Tag {};
struct less:Tag {};
struct greater:Tag {};
struct less_equal:Tag {};
struct greater_equal:Tag {};
struct equal_to:Tag {};
struct not_equal_to:Tag {};
struct logical_or:Tag {};
struct logical_and:Tag {};
struct bitwise_and:Tag {};
struct bitwise_or:Tag {};
struct bitwise_xor:Tag {};
struct shift_left_assign:Tag {};
struct shift_right_assign:Tag {};
struct multiplies_assign:Tag {};
struct divides_assign:Tag {};
struct modulus_assign:Tag {};
struct plus_assign:Tag {};
struct minus_assign:Tag {};
struct bitwise_and_assign:Tag {};
struct bitwise_or_assign:Tag {};
struct bitwise_xor_assign:Tag {};


template<typename Tag,typename...ARGS>
class Expr
{

public:
    template<typename...SRC>
    Expr(SRC const&...src){

    }
private:
};
template<typename T>
struct is_expr{
    enum{value=0};
};
template<typename Tag,typename...ARGS>
struct is_expr<Expr<Tag,ARGS...>>{
    enum{value=sizeof...(ARGS)};
};

#define BinaryOp(op,name)   \
template<typename L,typename R,typename=typename std::enable_if<is_expr<L>::value||is_expr<R>::value>::type>\
Expr<name,L,R> operator op(const L&l,const R&r)\
{\
   return  {std::forward<const L&>(l),std::forward<const R&>(r)};\
}

BinaryOp(<<,shift_left)
BinaryOp(>>,shift_right)
BinaryOp(*,multiplies)
BinaryOp(%,modulus)
BinaryOp(+,plus)
BinaryOp(-,minus)
BinaryOp(<,less)
BinaryOp(>,greater)
BinaryOp(<=,less_equal)
BinaryOp(>=,greater_equal)
BinaryOp(==,equal_to)
BinaryOp(!=,not_equal_to)
BinaryOp(||,logical_or)
BinaryOp(&&,logical_and)

}

.cpp:

#include "test.h"

using namespace TestFoo;//using namespace Appear bug
void test(){  
}

如果我删除BinaryOp(&&,logical_and),或者不在.cpp中使用命名空间,或者删除所有std :: forward,则成功编译。否则吃内存直到失败。

2 个答案:

答案 0 :(得分:1)

std::enable_if<isExpr<L>::value||isExpr<R>::value>

以上是有效类型,无论<> enable_if内的内容是什么。

typename std::enable_if<isExpr<L>::value||isExpr<R>::value>::type
当且仅当bool <>中的enable_if表达式为true时,

才是有效类型。

简而言之,你没有成功地做SFINAE,所以预期会出现奇怪的行为。特别是,您的重载运算符声称处理const bool&||const bool&和许多其他类型的业务,它没有业务搞乱。

我无法解码错误,但首先修复代码。

答案 1 :(得分:0)

使用

template<typename L, typename R, typename = typename std::enable_if<is_expr<L>::value &&    is_expr<R>::value>::type>
Expr<name, L, R> operator op(const L&l, const R&r);

你进入(编译器)递归operator ||:此运算符可以使用枚举 {{1来评估(未命名)枚举 is_expr<L>::value需要考虑is_expr<R>::value ...

解决方案是将is_expr<decltype(is_expr<L>::value)>::value替换为enum。 (见https://ideone.com/pqhmv1