我认为这个问题最可能的答案是,包含的运算符是被认为最有用的。如果没有人想要将某些内容添加到标准库中,它就不会被添加。
我认为断言C++0x中的运算符函数无用,因为lambda表达式更加优越,这是愚蠢的:确实,lambda表达式很棒而且 更加灵活,但有时使用命名的函数对象可以导致更简洁、更清晰、更易于理解的代码;此外,命名的函数对象可以是多态的,而lambda则不能。
当然,标准库运算符函数对象不是多态的(它们是类模板,所以操作数类型是函数对象类型的一部分)。不过编写自己的运算符函数对象并不是特别困难,而宏使这项任务非常简单:
namespace ops
template <typename T>
struct remove_reference<T&>
template <typename T>
struct remove_reference<T&&>
template <typename T>
T&& forward(typename remove_reference<T>::type&& a)
template <typename T>
T&& forward(typename remove_reference<T>::type& a)
template <typename T>
struct subscript_impl
template <typename U>
auto operator()(U&& u) const ->
decltype(detail::declval<U>()[detail::declval<T>()])
private:
mutable T arg_;
};
}
#define OPS_DEFINE_BINARY_OP(name, op) \
struct name \
\
}
OPS_DEFINE_BINARY_OP(plus, + );
OPS_DEFINE_BINARY_OP(minus, - );
OPS_DEFINE_BINARY_OP(multiplies, * );
OPS_DEFINE_BINARY_OP(divides, / );
OPS_DEFINE_BINARY_OP(modulus, % );
OPS_DEFINE_BINARY_OP(logical_or, || );
OPS_DEFINE_BINARY_OP(logical_and, && );
OPS_DEFINE_BINARY_OP(equal_to, == );
OPS_DEFINE_BINARY_OP(not_equal_to, != );
OPS_DEFINE_BINARY_OP(less, < );
OPS_DEFINE_BINARY_OP(greater, > );
OPS_DEFINE_BINARY_OP(less_equal, <= );
OPS_DEFINE_BINARY_OP(greater_equal, >= );
OPS_DEFINE_BINARY_OP(bitwise_and, & );
OPS_DEFINE_BINARY_OP(bitwise_or, | );
OPS_DEFINE_BINARY_OP(bitwise_xor, ^ );
OPS_DEFINE_BINARY_OP(left_shift, << );
OPS_DEFINE_BINARY_OP(right_shift, >> );
OPS_DEFINE_BINARY_OP(assign, = );
OPS_DEFINE_BINARY_OP(plus_assign, += );
OPS_DEFINE_BINARY_OP(minus_assign, -= );
OPS_DEFINE_BINARY_OP(multiplies_assign, *= );
OPS_DEFINE_BINARY_OP(divides_assign, /= );
OPS_DEFINE_BINARY_OP(modulus_assign, %= );
OPS_DEFINE_BINARY_OP(bitwise_and_assign, &= );
OPS_DEFINE_BINARY_OP(bitwise_or_assign, |= );
OPS_DEFINE_BINARY_OP(bitwise_xor_assign, ^= );
OPS_DEFINE_BINARY_OP(left_shift_assign, <<=);
OPS_DEFINE_BINARY_OP(right_shift_assign, >>=);
#define OPS_DEFINE_COMMA() ,
OPS_DEFINE_BINARY_OP(comma, OPS_DEFINE_COMMA());
#undef OPS_DEFINE_COMMA
#undef OPS_DEFINE_BINARY_OP
#define OPS_DEFINE_UNARY_OP(name, pre_op, post_op) \
struct name \
\
}
OPS_DEFINE_UNARY_OP(dereference, * , );
OPS_DEFINE_UNARY_OP(address_of, & , );
OPS_DEFINE_UNARY_OP(unary_plus, + , );
OPS_DEFINE_UNARY_OP(logical_not, ! , );
OPS_DEFINE_UNARY_OP(negate, - , );
OPS_DEFINE_UNARY_OP(bitwise_not, ~ , );
OPS_DEFINE_UNARY_OP(prefix_increment, ++, );
OPS_DEFINE_UNARY_OP(postfix_increment, , ++);
OPS_DEFINE_UNARY_OP(prefix_decrement, --, );
OPS_DEFINE_UNARY_OP(postfix_decrement, , --);
OPS_DEFINE_UNARY_OP(call, , ());
OPS_DEFINE_UNARY_OP(throw_expr, throw , );
OPS_DEFINE_UNARY_OP(sizeof_expr, sizeof , );
#undef OPS_DEFINE_UNARY_OP
template <typename T>
detail::subscript_impl<T> subscript(T&& arg)
#define OPS_DEFINE_CAST_OP(name, op) \
template <typename Target> \
struct name \
\
}
OPS_DEFINE_CAST_OP(const_cast_to, const_cast );
OPS_DEFINE_CAST_OP(dynamic_cast_to, dynamic_cast );
OPS_DEFINE_CAST_OP(reinterpret_cast_to, reinterpret_cast);
OPS_DEFINE_CAST_OP(static_cast_to, static_cast );
#undef OPS_DEFINE_CAST_OP
template <typename C, typename M, M C::*PointerToMember>
struct get_data_member
};
template <typename C, typename M, M C::*PointerToMember>
struct get_data_member_via_pointer
};
}
我省略了new
和delete
(以及它们的各种形式),因为使用它们编写异常安全代码太困难了 :-).
call
实现仅限于nullary operator()
重载; 使用可变参数模板,您可能可以将其扩展到支持更广泛的重载范围,但实际上最好使用lambda表达式或库(例如std::bind
)来处理更高级的调用场景。对于.*
和->*
实现也是如此。
剩下的可重载运算符都已提供,甚至包括像sizeof
和throw
这样的愚蠢的运算符。
【以上代码是独立的;不需要标准库头文件。我承认在rvalue引用方面还有点小白,所以如果我做错了什么,希望有人能让我知道。】