【问题标题】:Compile time nested loop using `std::integer_sequence`使用`std::integer_sequence`编译时间嵌套循环
【发布时间】:2021-06-20 06:19:27
【问题描述】:

在下面的代码中,我制定了一个编译时嵌套循环,它调用一个将数字打印到屏幕的print 函数。 1D 和 2D 版本工作,但 3D 版本触发 note: candidate template ignored: failed template argument deduction 错误。我做错了什么?

#include <functional>
#include <iostream>


// 1D processing.
template<int I>
constexpr void print()
{
    std::cout << I << std::endl;
}


template<int... Is>
constexpr void test(
        std::integer_sequence<int, Is...> is)
{
    (print<Is>(), ...);
}
// End 1D.


// 2D processing.
template<int I, int J>
constexpr void print()
{
    std::cout << I << ", " << J << std::endl;
}


template<int I, int... Js>
constexpr void print(
        std::integer_sequence<int, Js...> js)
{
    (print<I, Js>(), ...);
}


template<int... Is, int... Js>
constexpr void test(
        std::integer_sequence<int, Is...> is,
        std::integer_sequence<int, Js...> js)
{
    (print<Is, Js...>(js), ...);
}
// End 2D.


// 3D processing.
template<int I, int J, int K>
constexpr void print()
{
    std::cout << I << ", " << J << ", " << K << std::endl;
}

template<int I, int J, int... Ks>
constexpr void print(
        std::integer_sequence<int, Ks...> ks)
{
    (print<I, J, Ks>(), ...);
}


template<int I, int... Js, int... Ks>
constexpr void print(
        std::integer_sequence<int, Js...> js,
        std::integer_sequence<int, Ks...> ks)
{
    (print<I, Js, Ks...>(ks), ...);
}


template<int... Is, int... Js, int... Ks>
constexpr void test(
        std::integer_sequence<int, Is...> is,
        std::integer_sequence<int, Js...> js,
        std::integer_sequence<int, Ks...> ks)
{
    // THIS CALL FAILS DURING COMPILATION.
    (print<Is, Js..., Ks...>(js, ks), ...);
}
// End 3D.


int main()
{
    constexpr std::integer_sequence<int, 1, 2, 4, 8> is{};
    constexpr std::integer_sequence<int, 1, 2, 4> js{};
    constexpr std::integer_sequence<int, 32, 64> ks{};

    test(is); // 1D example.
    test(is, js); // 2D example.
    test(is, js, ks); // 3D example, FAILS.

    return 0;
}

【问题讨论】:

  • 不幸的是,我不确定为什么这会修复它,但是在 3D test() 函数中,省略了对 print() 的调用的第二个和第三个模板参数:(print&lt;Is&gt;(js, ks), ...);
  • @G.Sliepen。确实,这解决了它。知道为什么会很棒。
  • 我的猜测是,在print&lt;Is, Js..., Ks...&gt;() 中,Js...Ks... 之间的边界会丢失,但是如果让它根据参数自动推断,它确实知道边界在哪里。

标签: c++ templates c++17 template-meta-programming


【解决方案1】:

它失败的原因是你的函数print 的重载需要三个模板参数有两个可变参数模板参数包 template&lt;int I, int... Js, int... Ks&gt;。多个模板参数包只有在编译器可以从函数参数中扣除它们时才有效(参见temp.param/14):

函数模板的模板形参包后面不应有另一个模板形参,除非该模板形参可以从函数模板的形参类型列表 ([dcl.fct]) 推导出来或具有默认实参 ( [温度扣除])。 没有默认参数的演绎指南模板([temp.deduct.guide])的模板参数应可从演绎指南模板的参数类型列表中推导出来。

显式指定模板参数时,编译器将因此贪婪地将它们匹配到第一个参数包。 即使combining type and non-type parameters 也是如此。只有这样从非模板函数参数中进行推导

这意味着in your case

(print<Is, Js..., Ks...>(js, ks), ...);

实际上会忽略希望的候选模板

prog.cc:64:16: note: candidate template ignored: failed template argument deduction

有点像

print<I, Js..., Ks...>()

实际上会匹配类似的东西

template <int I, int... Ts>
constexpr void print()

Js...Ks... 将合并为 Ts... = {Js..., Ks...} 将没有任何指定的模板参数留给以下包 - 按照标​​准 - 必须可以从非模板函数参数中推导出它们。


为了了解为什么在初始代码中允许这样的语法可能会出现问题,只需想象一个具有两个参数包 TsSs 的模板函数,其中 Ss 可以从函数参数中扣除,但 @987654337 @ 不能被扣除,而是必须明确指定,

template <typename... Ts, typename... Ss>
void func(Ss... ss) {
  return;
}

被调用的

func<int,double>(int{1}, double{7.0});

这将是模棱两可的(Ts = {int, double}, Ss = {int, double}Ts = {}, Ss = {int, double}),因此会导致初始代码中的逻辑出现问题,但如果您贪婪地匹配参数,然后才从函数中扣除,则它是明确的(Ts = {int, double}, Ss = {int, double})论据。


在您的情况下,只需 删除最右边的参数包

(print<Is, Js...>(js, ks), ...);

两者都有

(print<Is>(js, ks), ...);

使编译成功,因为JsKs都可以从函数参数jsks中扣除。 Try it here!

【讨论】:

  • 好吧,想象一下,为了清楚起见,我想写出三个模板参数,我应该怎么做?
  • @Chiel 我认为没有办法这样做。如果您想更准确地了解将调用哪个函数,您可以将不同的 print 函数重命名为具有唯一名称。
  • 我很清楚调用了哪个函数。如果我省略模板参数,我只想知道幕后发生了什么,因为我的实际用例要复杂一些。您的回答解决了我的问题,但我并没有完全理解。
  • @Chiel 我明白了,我修改了我的答案。也许现在更清楚了。
  • @Chiel 题外话:看看你的 microhh 代码。真的很棒的东西!我是 DNS/LES 模拟、流体流动不稳定性和大气流动的忠实粉丝。你用什么进行可视化?只有 Python 并与 matplotlib 结合使用?
猜你喜欢
  • 2016-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-05
  • 2014-12-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
相关资源
最近更新 更多