重复调用一个带非类型模板参数的函数

4

我有一个带有非类型模板参数int的函数,如下所示:

template <int N>
int foo() { /*...*/ }

我想对从0到32的所有N值进行单元测试这个函数。我有一个函数int expected(int n),它接受相同的N值并返回预期值。实际上,我想要:

if (foo<0>() != expected(0)) { /* fail... */ }
if (foo<1>() != expected(1)) { /* fail... */ }
if (foo<2>() != expected(2)) { /* fail... */ }
// 30 more lines

我不想手动编写所有的33个测试用例,而且由于变量N是编译时确定的,我也不能轻易地使用运行时循环。
那么,在C++11中,我怎样才能简单地让编译器为我生成测试用例呢?请注意,这种方法不需要使用BOOST_PP_REPEAT式的技巧或代码生成。

你能澄清一下,如果测试失败,你是想继续还是中止吗? - M.M
我正在使用Catch2,测试看起来像REQUIRE(foo<0>() == expected(0)),它使用一些Catch2特定的魔法中止,并取决于命令行标志。虽然我并不想在这里引入Catch2宏的复杂性。这回答了你的问题吗,@M.M? - BeeOnRope
4个回答

5
你可以编写一个递归函数模板,使用完全特化来执行测试。例如:
template <int N>
void test() {
    test<N-1>();
    if (foo<N>() != expected(N)) { /* fail... */ }
}

template <>
void test<-1>() {
    // do nothing
}

并像这样运行它

test<32>();

2
在c++14中,你可以像这样做:

最初的回答

#include <type_traits>

template <int beg, int end> struct static_for {
    template <typename Fn> void operator()(Fn const& fn) const {
        if (beg < end) {
            fn(std::integral_constant<int, beg>());
            static_for<beg + 1, end>()(fn);
        }
    }
};

template <int n> struct static_for<n, n> {
    template <typename Fn> void operator()(Fn const& fn) const {}
};

template <int N> int foo() { /*...*/
    return N;
}

int main() {
    static_for<0, 32>()([&](auto i) {
        if (foo<i>() != i) { /* fail... */
        }
    });
    return 0;
}

1
这里是一个方法:

template<int N>
void f();

template<int... N>
void g(std::index_sequence<N...>)
{
  (f<N>(), ...);
}

可以这样调用:
g(std::make_index_sequence<33>());

编辑:

这里是一个实际检查测试是否成功完成的版本:

template<int N>
int f();

int expected(int n);

template<int... N>
bool g(std::index_sequence<N...>)
{
  return ((f<N>() == expected(N)) && ...);
}

这个用法如下:

g(std::make_index_sequence<33>()); // true if all tests are sucessful, false otherwise

1
“(f<N>(), ...);” 这部分在 C++11 或 C++14 下无法编译,至少对我来说是这样。它需要 C++17 吗? - BeeOnRope
为了匹配模板参数,您可以将index_sequence替换为integer_sequence<int,...> - user9400869
虽然不是很重要,但是... OP 要求一个序列“从0到32”,所以 std::make_index_sequence 的模板参数应该是 33,而不是 31(如果我没记错的话)。 - max66
@BeeOnRope - 是的:自C++17起,模板折叠是可用的。 - max66

0
一种可能的C++14解决方案,它“模拟”了C++17的模板折叠,并在第一次失败时中断f<N> != expected(N)
template <int N>
void f ();

template <int ... Is>
void g (std::integer_sequence<int, Is...>)
 {
   using unused = int[];

   bool ret { false };

   (void)unused { 0, (ret ? 0 : (ret = (f<Is>() != expected(Is)), 0))... }; 
 }

可以按以下方式调用

g(std::make_integer_sequence<33>());

对于 C++11 的解决方案,你需要一个替代品来代替仅在 C++14 中可用的 std::make_integer_sequence/std::integer_sequence


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接