用于单元测试的 C++ Template 模板

C++ Template template for unit testing

我正在尝试使用 C++ 的模板模板功能来减少我代码中的一个小单元测试段中的代码重复,但没有成功。我已经看到 these answers 类似的问题,但仍然无法弄清楚我的编译器告诉我的是什么。

我处理一些以不同精度进行数值处理的 classes,所以我认为我可以将重复代码泛化为模板函数,这样它就可以很容易地被 class 测试,如:

template<typename T, size_t S>
void CompareArrays(
    std::array<T, S> const &input,
    std::array<T, S> const &output) {...}

template <typename T>
void SomeClassTest::SomeClassIdentity() const {
    SomeClass<T> scZero;
    std::array<T, 1> const input = { 1 };
    auto output = scZero.Process(input);
    CompareArrays(input, output); // does the actual printing
}

然后,用模板模板函数测试很多类似SomeClassTest::SomeClassIdentity的操作:

template<template <typename> typename F>
void CheckAgainstNumericTypes() {
    std::cerr << "Testing with char...";
    F<char>();
    std::cerr << "Testing with short...";
    F<short>();
    std::cerr << "Testing with int...";
    F<int>();
    std::cerr << "Testing with float...";
    F<float>();
    std::cerr << "Testing with double...";
    F<double>();
}

问题是,每次我尝试调用 CheckAgainstNumericTypes,编译器都会拒绝并显示错误消息 "Invalid Template Argument for 'F', type expected",如下例所示:

void SomeClassTest::Test() const {
    std::cerr << "Some Class Tests #1 - base/identity case" << std::endl;
    CheckAgainstNumericTypes<SomeClassIdentity>();
    ...

我试着让 CheckAgainstNumericTypes 成为 SomeClass 的成员函数,在模板参数前面加上 SomeClass::,在它的末尾添加 (),甚至替换内部 typedef 来自 void(*F)(void);都无济于事。

我有两个问题,那么:

I'm experimenting with using C++'s template template features to reduce code duplication in a small unit test segment in my code, to no success

嗯...在我看来你还没有理解模板模板是什么。

如果我没理解错的话,你以为你写的时候

template <template <typename> typename F>
void CheckAgainstNumericTypes() {
    F<char>();
}

您正在调用函数 F<char>()

错了。

F<char>()是创建F<char>类型的临时对象,默认初始化。

你可以写F<char>{}而不是F<char>(),这样更清楚这不是模板函数的调用。

在这一点上,我不知道回应您的以下回答是否有意义,但是...

How can I transform my member function into a type so it is accepted by the template?

你不能。不是类型。

您可以在非类型模板参数中传递函数 - 或 class/struct 的静态成员(参见您链接的第一个答案)。

但是非静态方法(非静态成员函数)是另一种类型的野兽,需要 class 的对象才能调用它。

我能想到的最好的情况如下(注意:代码不是睾丸)

template <typename T, void (T::*M)()>
void foo (T & d)
 { d.*M(); }

你可以调用它

foo<SomeClassTest, &SomeClassTest::SomeClassIdentity>(someClassTestObject);

如您所见,您可以将 class 和指向方法的指针作为模板参数传递(类型模板参数第一个,值第二个)但是您需要一个类型的对象SomeClassTest 作为参数 (someClassTestObject).

如果你只想与特定 class 的成员一起工作(SomeClassTest,在你的情况下)你可以避免类型模板参数并简化如下

template <void (SomeClassTest::*M)()>
void foo (SomeClassTest & d)
 { d.*M(); }

// ...

foo<&SomeClassTest::SomeClassIdentity>(someClassTestObject);

Is there any other way of accomplishing the same desired syntactic result in SomeClassTest::Tests() without using template templates?

您不能使用模板-模板参数。