D语言中结构的运算符重载
operator overloading for structs in D language
我正在尝试在 D 语言中的 3D 向量之间实现诸如 +
、-
、*
、/
之类的算术运算(只是想知道它是否值得从 C++ 迁移到 D,我通常做 3D 图形和数值数学)。但是我可能遗漏了一些东西,下面的代码不起作用(我试图根据包含的参考文献来做)。
#!/usr/bin/env rdmd
import std.stdio;
// https://dlang.org/spec/operatoroverloading.html
// https://github.com/PhilippeSigaud/D-templates-tutorial/blob/master/D-templates-tutorial.md#u-op-v--------opbinarystring-s-vv-v-if-s--opv-op-u--------opbinaryrightstring-s-vv-v-if-s--op
struct vec3f{ float x,y,z; }
vec3f opBinary(string op)(vec3f a, vec3f b){
static if (op == "+"){ return vec3f(a.x+b.x,a.y+b.y,a.z+b.z); }
else static if (op == "*"){ return vec3f(a.x*b.x,a.y*b.y,a.z*b.z); }
else{ static assert(0, "Operator "~op~" not implemented"); }
}
struct vec3(T){ T x,y,z; }
auto opBinary(T,string op)(vec3!T a, vec3!T b){
static if (op == "+"){ return vec3!T(a.x+b.x,a.y+b.y,a.z+b.z); }
else static if (op == "*"){ return vec3!T(a.x*b.x,a.y*b.y,a.z*b.z); }
else{ static assert(0, "Operator "~op~" not implemented"); }
}
void main(){
//auto a = vec3!float(1.1,2.2,3.2);
//auto b = vec3!float(3.1,2.2,1.2);
auto a = vec3f(1.1,2.2,3.2);
auto b = vec3f(3.1,2.2,1.2);
writeln(a); writeln(b);
writeln( a+b );
}
opBinary
实现似乎编译得很好,但我尝试使用它时总是出错:
./operator_overload.d(27): Error: incompatible types for ((a) + (b)): 'vec3f' and 'vec3f'
Failed: ["dmd", "-v", "-o-", "./operator_overload.d", "-I."]
编辑 :我也尝试 mixin
与 this answer 相协调。同样的错误。
struct vec3f{ float x,y,z; }
vec3f opBinary(string op)(vec3f a,vec3f b)if(op=="+"||op=="-"||op=="*"||op=="/"){
mixin("return vec3f(a.x"~op~"b.x,a.y"~op~"b.y,a.z"~op~"b.z);");
}
编辑 2:是的,它必须是结构体的一部分(我不知道是否有任何方法可以使其成为独立的功能)。这很完美:
#!/usr/bin/env rdmd
import std.stdio;
struct vec3(T){
float x,y,z;
vec3!T opBinary(string op)(vec3!T b) if(op=="+"||op=="-"||op=="*"||op=="/"){
mixin("return vec3!T(x"~op~"b.x,y"~op~"b.y,z"~op~"b.z);");
}
}
void main(){
auto a = vec3!float(1.1,2.2,3.2);
auto b = vec3!float(3.1,2.2,1.2);
writeln(a); writeln(b);
writeln( a+b );
writeln( a*b );
}
C++ 和 D 的主要区别之一是 D 中用户指定的运算符始终是其中一个操作数的成员。对于二元运算符,如果结构在左侧,则运算符称为 opBinary
,对于右侧,则称为 opBinaryRight
。这是有充分理由的别无他法:它使运算符重载的实现变得非常复杂。您可能知道 C++ 在搜索运算符重载时会忽略名称空间,例如ostream&
和 int
之间的 <<
在命名空间 std
中。你不需要写
std::operator<<(std::operator<<(std::cout, "Hello World."), std::endl);
为
std::cout << "Hello World." << std::endl;
正因为如此。 D有一个模块系统。假设你有模块 a
给你类型 A
和模块 b
给你类型 B
,两者彼此没有直接关联。然后是这个模块 c
类型为 C
和一个运算符 *
类型为 A
and B
and returns a C
因为 C
与 A
和 B
相关。现在我导入 a
和 b
并在两个对象上使用 *
。编译器应该如何知道 c
?
我正在尝试在 D 语言中的 3D 向量之间实现诸如 +
、-
、*
、/
之类的算术运算(只是想知道它是否值得从 C++ 迁移到 D,我通常做 3D 图形和数值数学)。但是我可能遗漏了一些东西,下面的代码不起作用(我试图根据包含的参考文献来做)。
#!/usr/bin/env rdmd
import std.stdio;
// https://dlang.org/spec/operatoroverloading.html
// https://github.com/PhilippeSigaud/D-templates-tutorial/blob/master/D-templates-tutorial.md#u-op-v--------opbinarystring-s-vv-v-if-s--opv-op-u--------opbinaryrightstring-s-vv-v-if-s--op
struct vec3f{ float x,y,z; }
vec3f opBinary(string op)(vec3f a, vec3f b){
static if (op == "+"){ return vec3f(a.x+b.x,a.y+b.y,a.z+b.z); }
else static if (op == "*"){ return vec3f(a.x*b.x,a.y*b.y,a.z*b.z); }
else{ static assert(0, "Operator "~op~" not implemented"); }
}
struct vec3(T){ T x,y,z; }
auto opBinary(T,string op)(vec3!T a, vec3!T b){
static if (op == "+"){ return vec3!T(a.x+b.x,a.y+b.y,a.z+b.z); }
else static if (op == "*"){ return vec3!T(a.x*b.x,a.y*b.y,a.z*b.z); }
else{ static assert(0, "Operator "~op~" not implemented"); }
}
void main(){
//auto a = vec3!float(1.1,2.2,3.2);
//auto b = vec3!float(3.1,2.2,1.2);
auto a = vec3f(1.1,2.2,3.2);
auto b = vec3f(3.1,2.2,1.2);
writeln(a); writeln(b);
writeln( a+b );
}
opBinary
实现似乎编译得很好,但我尝试使用它时总是出错:
./operator_overload.d(27): Error: incompatible types for ((a) + (b)): 'vec3f' and 'vec3f'
Failed: ["dmd", "-v", "-o-", "./operator_overload.d", "-I."]
编辑 :我也尝试 mixin
与 this answer 相协调。同样的错误。
struct vec3f{ float x,y,z; }
vec3f opBinary(string op)(vec3f a,vec3f b)if(op=="+"||op=="-"||op=="*"||op=="/"){
mixin("return vec3f(a.x"~op~"b.x,a.y"~op~"b.y,a.z"~op~"b.z);");
}
编辑 2:是的,它必须是结构体的一部分(我不知道是否有任何方法可以使其成为独立的功能)。这很完美:
#!/usr/bin/env rdmd
import std.stdio;
struct vec3(T){
float x,y,z;
vec3!T opBinary(string op)(vec3!T b) if(op=="+"||op=="-"||op=="*"||op=="/"){
mixin("return vec3!T(x"~op~"b.x,y"~op~"b.y,z"~op~"b.z);");
}
}
void main(){
auto a = vec3!float(1.1,2.2,3.2);
auto b = vec3!float(3.1,2.2,1.2);
writeln(a); writeln(b);
writeln( a+b );
writeln( a*b );
}
C++ 和 D 的主要区别之一是 D 中用户指定的运算符始终是其中一个操作数的成员。对于二元运算符,如果结构在左侧,则运算符称为 opBinary
,对于右侧,则称为 opBinaryRight
。这是有充分理由的别无他法:它使运算符重载的实现变得非常复杂。您可能知道 C++ 在搜索运算符重载时会忽略名称空间,例如ostream&
和 int
之间的 <<
在命名空间 std
中。你不需要写
std::operator<<(std::operator<<(std::cout, "Hello World."), std::endl);
为
std::cout << "Hello World." << std::endl;
正因为如此。 D有一个模块系统。假设你有模块 a
给你类型 A
和模块 b
给你类型 B
,两者彼此没有直接关联。然后是这个模块 c
类型为 C
和一个运算符 *
类型为 A
and B
and returns a C
因为 C
与 A
和 B
相关。现在我导入 a
和 b
并在两个对象上使用 *
。编译器应该如何知道 c
?