链接器错误编译D模板

时间:2018-07-15 14:32:52

标签: d

这是一种简单语言的解释程序的一部分。该语言还包括字符串,列表,函数等,以及评估程序中的相应函数evalString,evalList等函数。仅显示Number子类和evalNumber函数。

Evaluator.evaluate函数调用Expr.eval,每个Expr子类都调用正确的Evaluator函数(evalNumberevalString,{{1 }}等)来计算表达式。

evalList

当我尝试构建它时,我得到

import std.stdio;
import std.string;

abstract class Expr {
    Out eval(Out)(Evaluator!Out evaluator);
}

class Number: Expr {
    double num;
    this(double _num) { num = _num; }

    override Out eval(Out)(Evaluator!Out evaluator) {
        return evaluator.evalNumber(this);
    }
}

class Evaluator(Out) {
    Out evaluate(Expr expr) {
        return expr.eval(this);          // ### Error is here ### 
    }   

    abstract Out evalNumber(Number number);
}   

class ExprPrinter: Evaluator!string {
    override string evalNumber(Number num) {
        return format("%s", num.num);
    }   
}   

void main() {
    Number n = new Number(5);
    auto printer = new ExprPrinter();

    writefln("Number: %s", printer.evaluate(n));
}   

如果我正确阅读了mangle,则编译器会说第19行上的example.o: In function `_D7example__T9EvaluatorTAyaZQp8evaluateMFCQBo4ExprZQBb': /home/neniu/projects/duover/source/example.d:19: undefined reference to `_D7example4Expr__T4evalTAyaZQkMFCQBf__T9EvaluatorTQBaZQpZQBh' collect2: error: ld returned 1 exit status Error: linker exited with status 1 (在代码中标记)是指未定义的函数,而是(在这种情况下){{1 }}函数应该就是那个函数。

我尝试更改第19行以包括Out专业化

expr.eval

但这根本没有区别。

我在这里想念什么?如何获得Number.eval的电话才能解析为return expr.eval!Out(this);

这与DMD 2.081.1。一起使用。

谢谢。

*&当我尝试构建它时,我得到

expr.eval(this)

如果我正确阅读了mangle,则编译器会说第19行的expr.eval(在代码中标记)是指未定义的函数,但是(在这种情况下)Number.eval函数是应该是那个功能。

我尝试更改第19行以包括Out专业化

返回expr.eval!Out(this);

但这根本没有区别。

我在这里想念什么?如何获取expr.expr(this)调用以解析为Number.eval?

这与DMD 2.081.1。一起使用。

谢谢。

*编辑*

我尝试使Number.eval抽象(对类本身使用example.o: In function `_D7example__T9EvaluatorTAyaZQp8evaluateMFCQBo4ExprZQBb': /home/neniu/projects/duover/source/example.d:19: undefined reference to `_D7example4Expr__T4evalTAyaZQkMFCQBf__T9EvaluatorTQBaZQpZQBh' collect2: error: ld returned 1 exit status Error: linker exited with status 1 限定符,因为这是每个子类都必须重写的功能:

Expr.eval

但是现在编译器抱怨

abstract

我不希望abstract class Expr { abstract Out eval(Out)(Evaluator!Out evaluator); } 是最终的。我没有做任何使example.d(5): Error: function `example.Expr.eval!string.eval` final functions cannot be abstract example.d(28): Error: template instance `example.Expr.eval!string` error instantiating example.d(35): instantiated from here: Evaluator!string 最终的事情。我不明白为什么这会使Expr.eval成为最终定论。如何使Expr.eval不是最终的,以便可以使它抽象,所以我可以-不,必须-覆盖它?

是否将声明为Expr.eval(“您必须重写此功能”)与声明为Expr.eval(“您不能重写此功能”)恰好相反?

2 个答案:

答案 0 :(得分:1)

  

不是将某些东西声明为抽象的(“您必须重写此函数”)与将其声明为最终的(“您无法重写此函数”)完全相反吗?

是的。但是模板化函数始终是最终的。 IMO,HSSFColor.getIndexHash().get(myCell.getCellStyle().getFillBackgroundColor())上应该有一条错误消息,但是显然编译器选择保持沉默。您需要将override Out eval(Out)(Evaluator!Out evaluator) {设为模板,或者将其移为非成员函数。

您要做的实际上是多次调度,该调度在OpenMethods中作为库实现。仅知道您所显示的代码,很难分辨这是否正是您所需要的。

答案 1 :(得分:0)

Expr.eval需要了解Out参数类型的唯一原因是因为我无法找到一种方法来获取Evaluator.evaluate来识别其运行时类型输入。如果我可以做类似的事情

// In class Evaualor. Maybe (Out) is a parameter the class, not the method.
Out evaluate(Out)(Expr e) {
    if (isType!Num(e)) {
        return evalNum(cast(Num) e);
    }
    else if (isType!Str(e)) {
        return evalStr(cast(Str) e);
    }
    else if (isType!List(e)) {
        return evalList(cast(List) e);
    }
    and so on
}

然后,Expr不需要了解Evaluator或它的evaluate方法发出的类型。

是否存在确定此类变量的实际运行时类型的方法?那会节省我一些时间。