简体   繁体   English

使用 `std::integer_sequence` 编译时嵌套循环

[英]Compile time nested loop using `std::integer_sequence`

In the code below, I have worked out a compile time nested loop that calls a print function that prints the number to screen.在下面的代码中,我制定了一个编译时嵌套循环,该循环调用一个将数字打印到屏幕的print函数。 The 1D and 2D version work, but the 3D version triggers a note: candidate template ignored: failed template argument deduction error. 1D 和 2D 版本有效,但 3D 版本触发note: candidate template ignored: failed template argument deduction错误。 What do I do wrong?我做错了什么?

#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;
}

The reason for it failing is that the overload of your function print which takes three template arguments has two variadic template parameter packs template<int I, int... Js, int... Ks> .它失败的原因是您的函数print的重载采用三个模板参数有两个可变参数模板参数包template<int I, int... Js, int... Ks> Multiple template parameter packs are only valid if the compiler can deduct them from the function arguments (see temp.param/14 ):多个模板参数包仅在编译器可以从函数参数中扣除它们时才有效(请参阅temp.param/14 ):

A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced from the parameter-type-list ([dcl.fct]) of the function template or has a default argument ([temp.deduct]).一个函数模板的模板参数包后面不能跟另一个模板参数,除非该模板参数可以从函数模板的参数类型列表([dcl.fct])中推导出来或者有一个默认参数([temp.fct])。扣除])。 A template parameter of a deduction guide template ([temp.deduct.guide]) that does not have a default argument shall be deducible from the parameter-type-list of the deduction guide template.没有默认参数的演绎指南模板([temp.deduct.guide])的模板参数应可从演绎指南模板的参数类型列表中演绎出来。

When explicitly specifying the template parameters the compiler will therefore match them greedily to the first parameter pack .因此,当明确指定模板参数时,编译器会将它们贪婪地匹配到第一个参数包 This is even the case when combining type and non-type parameters .甚至在组合类型和非类型参数时也是如此 Only then deduction occurs from non-template function arguments .只有这样才能从非模板函数参数中进行推导

This means in your case这意味着在你的情况下

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

will actually ignore the wished candidate template实际上会忽略希望的候选模板

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

as something like就像

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

would actually match something like实际上会匹配类似的东西

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

Js... and Ks... will be combined to Ts... = {Js..., Ks...} leaving none of the specified template parameters to the following packs as - by the standard - it must be possible to deduce them from the non-template function arguments. Js...Ks...将被组合到Ts... = {Js..., Ks...}没有任何指定的模板参数留给以下包 - 按照标​​准 - 它必须是可能的从非模板函数参数中推导出它们。


In order to see why allowing a syntax like in your initial code could be problematic just imagine a template function with two parameter packs Ts and Ss , where Ss can be deducted from the function arguments but Ts can't be deducted and instead has to specified explicitly,为了了解为什么在您的初始代码中允许类似的语法可能会出现问题,只需想象一个带有两个参数包TsSs的模板函数,其中Ss可以从函数参数中扣除,但Ts不能扣除,而是必须指定明确地,

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

which is called with这被称为

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

This would be ambiguous ( Ts = {int, double}, Ss = {int, double} or Ts = {}, Ss = {int, double} ) and therefore lead to problems with the logic in your initial code but is unambiguous ( Ts = {int, double}, Ss = {int, double} ) if you match the the parameters greedily and only then deduct from the function arguments.这将是模棱两可的( Ts = {int, double}, Ss = {int, double}Ts = {}, Ss = {int, double} ),因此会导致初始代码中的逻辑出现问题,但这是明确的( Ts = {int, double}, Ss = {int, double} ) 如果您贪婪地匹配参数,然后才从函数参数中扣除。


In your case simply removing the right-most parameter pack在您的情况下,只需删除最右边的参数包

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

or both of them两者兼而有之

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

makes the compilation succeed as Js and Ks can both be deducted from the function arguments js and ks .使编译成功,因为JsKs都可以从函数参数jsks扣除。 Try it here!在这里试试吧!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM