假设我想在两个对象之间组成一个特殊的运算符!+ C ++。 我想使用!+,例如,因为我认为它比任何其他运算符更有意义。
我能做的一件基本事情就是找到一个免费的,未使用的操作符并使用#define进行替换:
#define !+ %
class myclass
{
public:
int operator %(myclass &c)
{
return 3;
}
}
所以如果我后来写了像
这样的东西a!+b
使用myclass的a和b实例,它会起作用。
现在,有没有办法定义它而不是运算符,具有一些功能?类似的东西:
#define a!+b -> a.operatorexclamativeplus(b)
这会使翻译变得更加脏,并且可以允许这些新的“虚假运营商”中有无限数量的翻译!
答案 0 :(得分:10)
"现在,有没有办法定义它而不是运营商,有一些功能?"
不,!+
不构成预处理器宏的有效(正常)标识符。这些字符是为语言内在运算符保留的。
可用于宏定义的字符集是[_A-Za-z][_A-Za-z0-9]*
正则表达式语法 1 。
来自c++ standards definitions 草案部分
16个预处理指令
...
控制线:
...
# define
标识符替换列表换行符# define
标识符 lparen identifier-listopt)replacement-list new-line
# define
标识符 lparen ...)replacement-list new-line
# define
标识符 lparen identifier-list,...)replacement-list new-line
<强>更新强>
我已经尝试了一点,因为这实际上是一个有趣的问题,如果不是#define
&#d; 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()
请参阅live sample。
但是,由于operator precedence rules,这只适用于一元运算符(!
的优先级高于二进制+
),您想要的形式似乎没有实际上是可以实现的:
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;
}
<强>结论:强>
<强> ______________________________________________________________________________________ 强>
1)
关于标识符的前导下划线(_
,__
),请阅读this answer中提到的标准部分,但这些部分在语法上是有效的。
答案 1 :(得分: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;
}
答案 2 :(得分:1)
您无法在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 ++编译器非常高兴。
你永远不会知道,你的新语言甚至可能会流行起来。有时它们会这样做。
答案 3 :(得分:0)
无法在C ++中定义自己的唯一运算符。
我还说其他语言可能会这样做。
答案 4 :(得分:0)
其他人解释了这种不可能性。但是,你也问过这个功能是什么,是的,那个&#39; s&#39;我先走的路。你只需将你想要的任何操作放入(自由/未绑定)函数中,给它一个合适的名称,这不会给读者造成任何混淆。
现在,如果您认为您的特殊情况足以打破规则,那么您可以执行以下操作:
int x = 23 /strangeop/ 42;
这里,strangeop
实际上是一个对象,并且对于此类型的对象和整数,存在重载的/
运算符。第一个这样的运算符求值为一个代理对象,该对象保持对整数操作数的引用,但也定义了重载的/
运算符,在该运算符中它接收另一个操作数,然后返回奇怪操作的实际结果。请注意,您可以在此处使用任何二元运算符,这更多是个人选择的问题。
注意:
#define STRANGEOP /strangeop/
。strange_op(23, 43)
进行比较,并考虑更好的可读性。