是否可以制作自定义操作符,以便您可以执行此类操作?
if ("Hello, world!" contains "Hello") ...
注意:这是一个单独的问题:“这是一个好主意......”;)
答案 0 :(得分:31)
有一些公开的工具可以帮助您。两者都使用预处理器代码生成来创建实现自定义运算符的模板。这些运算符由一个或多个内置运算符和标识符组成。
由于这些实际上不是自定义运算符,而只是运算符重载的技巧,因此有一些注意事项:
_
,o
或类似的简单字母数字。当我为此目的在我自己的图书馆工作时(见下文),我遇到了这个项目。以下是创建avg
运算符的示例:
#define avg BinaryOperatorDefinition(_op_avg, /)
DeclareBinaryOperator(_op_avg)
DeclareOperatorLeftType(_op_avg, /, double);
inline double _op_avg(double l, double r)
{
return (l + r) / 2;
}
BindBinaryOperator(double, _op_avg, /, double, double)
以an exercise in pure frivolity开头的内容成了我对这个问题的看法。这是一个类似的例子:
template<typename T> class AvgOp {
public:
T operator()(const T& left, const T& right)
{
return (left + right) / 2;
}
};
IDOP_CREATE_LEFT_HANDED(<, _avg_, >, AvgOp)
#define avg <_avg_>
答案 1 :(得分:11)
Sander Stoks在'Syntactic Aspartame'中彻底探讨了一种允许您使用以下格式的方法:
if ("Hello, world!" <contains> "Hello") ...
本质上,你需要一个带有运算符'&lt;'的代理对象和'&gt;'超载。代理完成所有工作; 'contains'可以只是一个没有自己行为或数据的单身人士。
// Not my code!
const struct contains_ {} contains;
template <typename T>
struct ContainsProxy
{
ContainsProxy(const T& t): t_(t) {}
const T& t_;
};
template <typename T>
ContainsProxy<T> operator<(const T& lhs, const contains_& rhs)
{
return ContainsProxy<T>(lhs);
}
bool operator>(const ContainsProxy<Rect>& lhs, const Rect& rhs)
{
return lhs.t_.left <= rhs.left &&
lhs.t_.top <= rhs.top &&
lhs.t_.right >= rhs.right &&
lhs.t_.bottom >= rhs.bottom;
}
答案 2 :(得分:2)
为了更准确一点,C ++ 本身仅支持创建现有操作的新重载,而不是创建新的操作符。有些语言(例如ML及其大部分后代)允许您创建全新的运算符,但C ++不是其中之一。
从外观上看,(至少)其他答案中提到的CustomOperators库也不支持完全自定义的运算符。至少如果我正确地阅读了这些内容,它会(内部)将您的自定义运算符转换为现有运算符的重载。这会使事情变得更容易,但会牺牲一些灵活性 - 例如,当您在ML中创建新运算符时,您可以使其优先于任何内置运算符的优先级。
答案 3 :(得分:0)
你的建议仅仅是语法糖:
if( contains( "Hello, world!", "Hello" ) ...
实际上已经有一个函数可以在cstring和std :: string中执行此操作。这或许有点像回答“这是一个好主意吗?”但并不完全;而是问“为什么你需要/想要?”
答案 4 :(得分:0)
从技术上讲,没有。也就是说,您无法扩展operator+
,operator-
等的集合。但是你在你的例子中提出的建议是另外的。你想知道是否有“包含”的定义,string-literal "contains" string-literal
是一个表达式,具有非平凡的逻辑(#define contains ""
是一个简单的例子)。
表达式string-literal X string-literal
的表达式不多。这是因为字符串文字本身就是表达式。因此,您正在寻找expr X expr
形式的语言规则。其中有很多,但它们都是运营商的规则,而那些不适用于字符串。尽管有明显的实现,"Hello, " + "world"
不是有效的表达式。那么,string-literal X string-literal
中的X还有什么?它本身不能表达。它不能是typename,typedef名称或模板名称。它不能是函数名称。它实际上只能是一个宏,它是唯一剩下的命名实体。为此,请参阅“是(好的,有点)”答案。
答案 5 :(得分:0)
我创建了以下两个宏:
#define define const struct
#define operator(ReturnType, OperatorName, FirstOperandType, SecondOperandType) OperatorName ## _ {} OperatorName; template <typename T> struct OperatorName ## Proxy{public:OperatorName ## Proxy(const T& t) : t_(t){}const T& t_;static ReturnType _ ## OperatorName ## _(const FirstOperandType a, const SecondOperandType b);};template <typename T> OperatorName ## Proxy<T> operator<(const T& lhs, const OperatorName ## _& rhs){return OperatorName ## Proxy<T>(lhs);}ReturnType operator>(const OperatorName ## Proxy<FirstOperandType>& lhs, const SecondOperandType& rhs){return OperatorName ## Proxy<FirstOperandType>::_ ## OperatorName ## _(lhs.t_, rhs);}template <typename T> inline ReturnType OperatorName ## Proxy<T>::_ ## OperatorName ## _(const FirstOperandType a, const SecondOperandType b)
然后,您只需要定义自定义运算符即可,如以下示例所示:
define operator(bool, myOr, bool, bool) { // Arguments are the return type, the name of the operator, the left operand type and the right operand type, respectively
return a || b;
}
#define myOr <myOr> // Finally, you have to define a macro to avoid to put the < and > operator at the start and end of the operator name
一旦您设置了操作员,就可以将其用作预定义的操作员:
bool a = true myOr false;
// a == true
答案 6 :(得分:0)
正如其他人所指出的,遗憾的是您无法编写自定义运算符,但使用宏您可以获得类似的行为。使用 c 样式转换实际上非常简单,请参见下文。
4 to 5
此处 YYYY-dd-mm
将返回 To_Range 类型的对象。 (Slicing_To_End) 将 5 投射到 Slicing_To_End。现在编译器想要找到一个合适的 == 运算符。唯一的一个是我们的自定义运算符,它将第一个位置和第二个 Slicing_To_End 中的整数作为输入,并返回我们的 To_Range 类型。当然,您也可以返回其他类型,例如 int、float。