【问题标题】:operator overloading for structs in D languageD语言结构的运算符重载
【发布时间】:2017-08-19 17:10:53
【问题描述】:

我正在尝试在 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."]

编辑:我还尝试了 mixinthis 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 );
}

【问题讨论】:

  • 我不确定,但是重载的运算符不需要是相应结构的成员吗?尝试将其移动到结构中(进行相关编辑,ofc)。

标签: templates struct operator-overloading d


【解决方案1】:

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 的模块*,它采用AB 类型并返回C,因为C 涉及AB。现在我导入ab 并在两个对象上使用*。编译器应该如何知道c

【讨论】:

  • 一个小修正:C++ 在查找函数时不会忽略命名空间。它使用参数依赖查找,尝试在其参数的命名空间中解析函数。
  • 它不需要将命名空间注释给操作符,而它对函数这样做。但是,是的,依赖于参数的查找不是 D 中的东西。它也不太可能成为未来的功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
相关资源
最近更新 更多