模板别名导致单元测试失败
template alias causes unit test failure
我是 D 的新手,我对利用它所提供的一切非常感兴趣。我目前正在将我在 C++ 中拥有的大型代码库转换为用于教育的 D。虽然我才刚刚开始,但我遇到了一些奇怪的矛盾。我有一个带有构造函数的模板结构和该构造函数的单元测试(希望我使用正确)。似乎验证正确。但是,如果我在文件底部为特定模板化结构创建类型别名,我会在单元测试中遇到异常。
main.d
import math;
int main() {
return 0;
}
math.d
import std.math;
import std.stdio;
struct Vector2(T) {
T[2] vec = [0, 0];
@property const T x() {return vec[0];}
@property inout(T) x(inout(T) val) {return vec[0] = val;}
@property const T y() {return vec[1];}
@property inout(T) y(inout(T) val) {return vec[1] = val;}
this(T x, T y) {
this.x = x;
this.y = y;
}
unittest {
Vector2!int a = Vector2!int(2, 2);
assert(a.x == 2 && a.y == 2);
Vector2!float b = Vector2!float(2.2, 2.2);
assert(b.x == 2.2 && b.y == 2.2); // <-- this line excepts given alias
}
}
// if this is not here, no problem.
// if it is here "core.exception.AssertError@math.d(21): unittest failure"
alias Vector2f = Vector2!float;
为什么存在别名会导致单元测试失败?我正在使用这个命令来构建:
dmd -unittest main.d math.d
我使用Windows10,DMD版本2.070.2,和msys2shell
模板本身没有(通常不能)进行单元测试。只有它的实例化实例是。
由于2.2
不能用浮点型变量精确表示,所以最接近2.2
的double
和[=14=是不一样的] 最接近 2.2
。如果将行更改为以下内容(2.2f
是浮点常量,2.2
是双精度常量),测试成功:
Vector2!float b = Vector2!float(2.2f, 2.2f);
assert(b.x == 2.2f && b.y == 2.2f); // <-- no exception
一般情况下,应该避免直接比较浮点变量,除非 really know what they are doing. In D, one may want to use std.math.approxEqual 比较它们。
如果一个模板没有被实例化,它甚至不会被编译超出一些基本的语法检查。模板化类型是类型的 模板 ,而不是实际类型。因此,Vector2
不是类型,而 Vector2!int
是。您将别名声明为 Vector2!float
的事实就是实例化 Vector2
并使其被完全编译的原因 - 包括 unittest
块。如果模板未实例化,则模板内的 unittest
块不会比模板的其余部分编译得更多,并且它将被编译到模板的每个实例中(这就是为什么它通常不是一个好的原因将 unittest
块放入模板中的想法)。
因此,至少,您应该在实例化模板的模板外部放置一个 unittest
块。如果你想避免将单元测试编译到模板的每个实例中,那么你应该将它们全部移出模板(大概用注释标记以指示它们与哪些函数一起使用),这将使模板适当地实例化和测试。如果您不关心在模板的每个实例化中都有一份单元测试的副本,并且想在它们测试的函数之后立即离开测试(就像您通常那样),那么您只需要放置一个 unittest
块在模板之后立即实例化它,以便模板内部的 unittest
块得到编译和 运行.
有 a proposal 用于添加功能以允许在模板内部使用特殊的 unittest
块,这些块实际上不是模板的一部分,并且功能类似于模板外部的 unittest
块template 将起作用(但仍将紧挨着被测试的函数),但尚未决定是否将它或类似的东西添加到语言中以解决此问题。因此,在此期间,我建议不要将 unittest
块放在模板内,但无论如何,您需要确保模板在自身外部实例化,以便对其进行编译和测试。
附带说明一下,您真的不应该将浮点值与 ==
或 !=
进行比较,正如这篇经典论文中所解释的那样:http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html. Using approxEqual
会是一个更好的选择.
我是 D 的新手,我对利用它所提供的一切非常感兴趣。我目前正在将我在 C++ 中拥有的大型代码库转换为用于教育的 D。虽然我才刚刚开始,但我遇到了一些奇怪的矛盾。我有一个带有构造函数的模板结构和该构造函数的单元测试(希望我使用正确)。似乎验证正确。但是,如果我在文件底部为特定模板化结构创建类型别名,我会在单元测试中遇到异常。
main.d
import math;
int main() {
return 0;
}
math.d
import std.math;
import std.stdio;
struct Vector2(T) {
T[2] vec = [0, 0];
@property const T x() {return vec[0];}
@property inout(T) x(inout(T) val) {return vec[0] = val;}
@property const T y() {return vec[1];}
@property inout(T) y(inout(T) val) {return vec[1] = val;}
this(T x, T y) {
this.x = x;
this.y = y;
}
unittest {
Vector2!int a = Vector2!int(2, 2);
assert(a.x == 2 && a.y == 2);
Vector2!float b = Vector2!float(2.2, 2.2);
assert(b.x == 2.2 && b.y == 2.2); // <-- this line excepts given alias
}
}
// if this is not here, no problem.
// if it is here "core.exception.AssertError@math.d(21): unittest failure"
alias Vector2f = Vector2!float;
为什么存在别名会导致单元测试失败?我正在使用这个命令来构建:
dmd -unittest main.d math.d
我使用Windows10,DMD版本2.070.2,和msys2shell
模板本身没有(通常不能)进行单元测试。只有它的实例化实例是。
由于
2.2
不能用浮点型变量精确表示,所以最接近2.2
的double
和[=14=是不一样的] 最接近2.2
。如果将行更改为以下内容(2.2f
是浮点常量,2.2
是双精度常量),测试成功:Vector2!float b = Vector2!float(2.2f, 2.2f); assert(b.x == 2.2f && b.y == 2.2f); // <-- no exception
一般情况下,应该避免直接比较浮点变量,除非 really know what they are doing. In D, one may want to use std.math.approxEqual 比较它们。
如果一个模板没有被实例化,它甚至不会被编译超出一些基本的语法检查。模板化类型是类型的 模板 ,而不是实际类型。因此,Vector2
不是类型,而 Vector2!int
是。您将别名声明为 Vector2!float
的事实就是实例化 Vector2
并使其被完全编译的原因 - 包括 unittest
块。如果模板未实例化,则模板内的 unittest
块不会比模板的其余部分编译得更多,并且它将被编译到模板的每个实例中(这就是为什么它通常不是一个好的原因将 unittest
块放入模板中的想法)。
因此,至少,您应该在实例化模板的模板外部放置一个 unittest
块。如果你想避免将单元测试编译到模板的每个实例中,那么你应该将它们全部移出模板(大概用注释标记以指示它们与哪些函数一起使用),这将使模板适当地实例化和测试。如果您不关心在模板的每个实例化中都有一份单元测试的副本,并且想在它们测试的函数之后立即离开测试(就像您通常那样),那么您只需要放置一个 unittest
块在模板之后立即实例化它,以便模板内部的 unittest
块得到编译和 运行.
有 a proposal 用于添加功能以允许在模板内部使用特殊的 unittest
块,这些块实际上不是模板的一部分,并且功能类似于模板外部的 unittest
块template 将起作用(但仍将紧挨着被测试的函数),但尚未决定是否将它或类似的东西添加到语言中以解决此问题。因此,在此期间,我建议不要将 unittest
块放在模板内,但无论如何,您需要确保模板在自身外部实例化,以便对其进行编译和测试。
附带说明一下,您真的不应该将浮点值与 ==
或 !=
进行比较,正如这篇经典论文中所解释的那样:http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html. Using approxEqual
会是一个更好的选择.