首页 > 解决方案 > 用于单元测试的 C++ 模板模板

问题描述

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

我处理了一些以不同精度进行数值处理的类,所以我认为我可以将重复的代码推广到模板化函数,这样它就可以很容易地被类测试调用,如下所示:

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时,编译器都会拒绝并显示错误消息“'F' 的模板参数无效,预期类型”,如下例所示:

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

我尝试制作CheckAgainstNumericTypes一个成员函数SomeClass,在模板参数前面加上SomeClass::,添加()到它的末尾,甚至用 ; 替换typedef内部void(*F)(void)。一切都无济于事。

那我有两个问题:

标签: c++templatesc++17template-templates

解决方案


我正在尝试使用 C++ 的模板模板功能来减少代码中的一个小单元测试段中的代码重复,但没有成功

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

如果我理解正确,你认为当你写

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

你正在调用一个函数F<char>()

错误的。

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

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

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

如何将我的成员函数转换为类型以便模板接受它?

你不能。不像类型。

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

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

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

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

你可以称之为

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

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

如果您只想使用特定类的成员(SomeClassTest在您的情况下),您可以避免使用类型模板参数并简化如下

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

// ...

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

有没有其他方法可以在 SomeClassTest::Tests() 中实现相同的语法结果而不使用模板模板?

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


推荐阅读