#在c++中定义一个特殊的运算符
#define a special operator in c++
说我想编一个特殊的运算符!+在C++中两个对象之间。我想使用!+,例如,因为我认为它比任何其他运算符都更有意义。
我可以做的一件基本的事情是找到一个免费的、未使用的运算符,并使用#define:进行替换
#define !+ %
class myclass
{
public:
int operator %(myclass &c)
{
return 3;
}
}
所以如果我以后写一些类似的东西
a!+b
有了myclass的a和b实例,它就可以工作了。
现在,有没有什么方法可以定义它,用一个运算符,用一些函数?类似于:
#define a!+b -> a.operatorexclamativeplus(b)
这将使翻译不那么肮脏,并允许潜在的无限数量的这些新的"假操作员"!
"现在,有什么方法可以定义它,而不是用运算符,用一些函数?"
否,!+
不构成预处理器宏的有效(正常)标识符。这些字符是为语言内部运算符保留的。
可用于宏定义的字符集是[_A-Za-z][_A-Za-z0-9]*
regex语法1。
根据c++标准定义草案部分
16预处理指令
控制行:
…# define
标识符替换列表新行# define
标识符lparen标识符列表选择)替换列表新行# define
标识符lparen…)替换列表新行# define
标识符lparen标识符列表,…)更换清单新品
更新:
我已经对此进行了一些实验,因为这实际上是一个有趣的问题,如果不是#define
’d宏,我们可以为c++中的类使用重载内部运算符函数。
我发现实际上存在一些可能的(但可能很奇怪,而且行为出乎意料)选项,通过链接内在运算符并保持状态来重载它们的组合。对于新引入的运营商,你能得到的最接近的东西可能是:
class Foo {
enum OpState { None , PlusState , NotState };
public:
Foo& operator+() {
cout << "operator+()" << endl;
opState = PlusState;
return *this;
}
Foo& operator!() {
cout << "operator!()" << endl;
switch(opState) {
case PlusState:
operatorexclamativeplus();
break;
default:
opState = NotState;
break;
}
return *this;
}
private:
Foo& operatorexclamativeplus() {
cout << "operatorexclamativeplus()" << endl;
opState = None;
return *this;
}
Foo& operatorexclamativeplus(const Foo& rhs) {
cout << "operatorexclamativeplus(const Foo& rhs)" << endl;
opState = None;
return *this;
}
OpState opState;
};
int main() {
Foo x;
Foo z = !+x;
return 0;
}
输出
operator+()
operator!()
operatorexclamativeplus()
参见活样本。
尽管,由于运算符优先级规则,这只适用于一元运算符(!
的优先级高于二进制+
),但您想要的形式似乎实际上无法实现:
class Foo {
// ...
public:
// Provide an additional binary 'operator+()'
friend Foo& operator+(Foo& lhs, const Foo& rhs) {
cout << "operator+(Foo& lhs, const Foo& rhs)" << endl;
if(lhs.opState == NotState) {
return lhs.operatorexclamativeplus(rhs);
}
return lhs;
}
// ...
};
int main() {
Foo x;
Foo y;
Foo z = y !+ x;
return 0;
}
看到这个悲惨的失败。
结论:
- 一些重载的内部运算符组合可能是语法上可能的,关于它们的优先定义,以及保持lvalues的状态
- 这可能不是一个很好的主意,试图超载内在运算符行为,引入了全新的语义
______________________________________________________________________________________
1)关于标识符的前导下划线(_
,__
),请阅读本答案中提到的标准部分,这些部分在语法上是有效的。
从技术上讲,C++不允许您定义新的运算符。但是,您可以从现有操作符中获得任何想要的行为,包括具有新操作符的外观
(不是说这是个好主意,只是回答了"有可能吗?")
你永远不能写a !+ b
,因为!
不是二进制运算符
但是你可以写a +! b
,因为+
是二进制的,而!
是一元的
您可以重新定义这些运算符,以便a +! b
返回您想要的内容。
诀窍是定义一元运算符以返回辅助对象,然后定义二元运算符以作用于该辅助对象。
作为一个例子,下面是将创建一个+的外观的代码!操作人员这个新+!操作员返回左手边加右手边的十倍。所以…1+!2将得到12。
class MyClass
{
public:
int value;
};
class MyClassHelper
{
public:
int value;
};
// define a unary ! operator that takes a right hand MyClass object
const MyClassHelper operator!(const MyClass right)
{
// this operator just copies the value into a MyClassHelper object
MyClassHelper answer;
answer.value = right.value;
return answer;
}
// define a binary + operator that takes a left hand MyClass object and a right hand MyClassHelper object
const MyClass operator+(const MyClass left, const MyClassHelper right)
{
// this operator should return the value you want the +! operator to return
MyClass answer;
answer.value = left.value * 10 + right.value;
return answer;
}
int main()
{
// initialize a and b
MyClass a, b;
a.value = 1;
b.value = 2;
// this line will now compile with the +! operator
MyClass c;
c = a +! b;
cout << "c = " << c.value << endl;
return 0;
}
您不能在C/C++中定义新的运算符。标准不允许这样做,宏和模板的元编程功能也不足以绕过它
但这阻止了Brad Cox(Objecte-C)和Bjorne Stroustrup(C++/cfront)吗?当然不是!Bertrand Meyer也做到了(Eiffel),Kernighan和Plauger(RATFOR)也做到了。
在C/C++中添加新语言功能(如新运算符)的方法是创建自己的预处理器。您可以使用宏处理语言或编写自己的编译器,以便输入:
if (something) {
a!+b
}
翻译成:
if (something) {
a.operatorexclamativeplus(b);
}
C++编译器非常高兴。
你永远不会知道,你的新语言甚至可能会流行起来。有时确实如此。
在C++中不可能定义自己的唯一运算符。
我也认为在其他语言中也可以这样做。
其他人解释了这是不可能的。然而,你也问过如何将其作为一个函数,是的,这是"我首先要做的"。你只需将你想要的任何操作放入一个(自由/未绑定)函数中,给它一个合适的名称,这不会给读者带来任何困惑。
现在,如果你认为你的特殊情况足够特殊,足以违反规则,那么你可以做以下事情:
int x = 23 /strangeop/ 42;
这里,strangeop
实际上是一个对象,并且对于这种类型的对象和整数存在重载的/
运算符。第一个这样的运算符计算为一个代理对象,该代理对象保留对整数操作数的引用,但也定义了重载的/
运算符,在该运算符中它接收另一个操作数,然后返回奇异运算的实际结果。请注意,您可以在这里使用任何二进制运算符,这更多是个人选择的问题。
注:
- 您可以通过
#define STRANGEOP /strangeop/
进一步了解这一点 - 使用它,您还可以定义一元奇异运算符,不过您仍然需要一个二进制运算符来重载
- 将其与
strange_op(23, 43)
进行比较,并考虑其更好的可读性 - 我还没有找到一个真正需要这种技术的案例,所以我不能告诉你它是否有效,以及它的实际限制在哪里
- 一个关于在C++中重载布尔运算符的问题
- 使用运算符 [] 引用 std::vector 上最后一个元素时出现问题<>
- 为 std::variant 提供一个运算符 ==
- 一元*运算符的操作数是否期望一个 prvalue
- 为什么我可以在不重载 "=" 运算符的情况下将一个对象分配给另一个对象?
- 我在 .h 中有一个枚举类,并且在.cpp错误中有一个运算符重载:与"运算符<<不匹配
- C++ STD 函数运算符:有没有一种方法可以通过函数将一个向量映射到另一个向量上?
- 运算符重载:"operator+"必须采用零个或一个参数
- 重载运算符*以获取对另一个类的实例的引用
- 使用 scope 运算符 (::) 引用另一个文件中的类
- 我重载了 << 和 = 运算符。为什么当我将一个对象分配给另一个对象并尝试打印它时,我会被打印出来?
- 在一个指令中声明更多指针的运算符优先级
- 为什么有条件编译运算符模板会更改另一个运算符的可用性?
- 我重载了一个运算符*()函数来计算两个矩阵的总和,但编译器提示此错误
- 基于范围的循环使用另一个运算符
- 在C++中,我可以使用箭头运算符访问另一个运算符吗
- 卡住了---用C++创建一个运算符模板
- 为什么一个运算符的操作数需要具有相同的类型
- 是否可以为 C++ 的字符串类创建一个运算符+函数?并连接"literals"?
- 如何为 boost::tuple 编写一个 '<<' 运算符?