链接器在编译D模板时出错

链接器在编译D模板时出错,d,D,这是一种简单语言的解释器的一部分。该语言还包括字符串、列表、函数等以及计算器中相应的函数evalString、evalList等函数。仅显示Number子类和evalNumber函数 Evaluator.evaluate函数调用Expr.eval,每个Expr子类调用正确的Evaluator函数(evalNumber,evalString,evalList等)对表达式求值 import std.stdio; import std.string; abstract class Expr {

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

Evaluator.evaluate
函数调用
Expr.eval
,每个
Expr
子类调用正确的
Evaluator
函数(
evalNumber
evalString
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));
}   
当我试图建造它时,我得到了

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
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
如果我读错了,编译器会说第19行的
expr.eval
引用了一个未定义的函数(在本例中,
Number.eval
函数应该是该函数)

我试着将第19行改为包括我们的专业

return expr.eval!Out(this);
但这根本没什么区别

我错过了什么?如何获得
expr.eval(this)
调用以解析为
Number.eval

这是与DMD2.081.1

多谢各位

*&当我试图建造它时,我得到了

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
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
如果我读错了,编译器会说第19行的expr.eval(代码中有标记)引用了一个未定义的函数,但(在本例中)Number.eval函数应该是该函数

我试着将第19行改为包括我们的专业

return expr.eval!Out(this);
返回expr.eval!(这个)

但这根本没什么区别

我错过了什么?如何让expr.expr(此)调用解析为Number.eval

这是与DMD2.081.1

多谢各位

*编辑*

我尝试将
Expr.eval
abstract(带或不带
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
不是最终版本,这样我就可以抽象它,这样我就可以——不,必须——重写它

将某物声明为
抽象
(“您必须重写此函数”)与将其声明为
最终
(“您不能重写此函数”)是否完全相反

将某物声明为抽象(“您必须重写此函数”)不是与将其声明为最终(“您不能重写此函数”)完全相反吗

是的。但是模板函数总是最终的。在我看来,
override Out eval(Out)(Evaluator!Out Evaluator){
,应该有一条错误消息,但显然编译器选择保持沉默。您需要使
eval
不是模板,或者移动它,使其不是成员函数


您所做的基本上是多重分派,它在中作为一个库实现。只知道您显示的代码,很难判断这是否正是您所需要的。

Expr.eval
需要了解
Out
参数类型的唯一原因是因为我无法找到获取
Evaluator.ev的方法aluate
以识别其输入的运行时类型。如果我可以执行以下操作

// 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
将不需要了解
求值器
或其
求值
方法发出的类型


有没有这样一种方法来确定这类变量的实际运行时类型?这将节省我一些时间。

这将解释为什么
eval.expr
没有定义。它没有定义是因为它是
抽象的
,不能重新定义是因为它是
最终的
(因为它是一个模板)。我同意编译器发出的嘎嘎声会很好。Out返回类型是一个参数,因为某些计算器/阶段(例如宏扩展、常量折叠)为下一阶段发出
Expr
s,而某些(漂亮的打印机和其他语言的翻译程序)发出字符串。迭代非常简单,我可以将其克隆到单独的转换器和转换器基类中,并从中派生出每个阶段。Ooo。OpenMethods看起来可能正是我所追求的。我确实考虑了Clojure协议和多个分派,但不确定如何表达它。我确实需要进一步探索这一点但它看起来只是一张票,再次感谢您。另一个选项是将
Expr
a
struct
(而不是类)并添加一个
ExprType type
字段,其中
ExprType
数字
字符串
列表
等的枚举。可以在运行时(在我的代码中,而不是在编译时在编译器的代码中)检查表达式类型并调度正确的计算器函数,并且因为
struct Expr
无论如何都不能被子类化,所以模板化方法的
final
性质是没有意义的,不是问题。