[英]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,为了了解为什么在您的初始代码中允许类似的语法可能会出现问题,只需想象一个带有两个参数包
Ts
和Ss
的模板函数,其中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
.使编译成功,因为
Js
和Ks
都可以从函数参数js
和ks
扣除。 Try it here!在这里试试吧!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.