从 make_integer_sequence 到 integer_sequence 的转换错误

问题描述

以下程序无法编译:

#include <utility>
#include <iostream>

#define N 4

template <unsigned int I>
unsigned int g() { return I; }

template <unsigned int... I>
unsigned int f(std::integer_sequence<unsigned int,I...> = std::make_integer_sequence<unsigned int,N>{})
{
  return (g<I>() + ...);
}

int main()
{
  std::cout << f() << std::endl;
  return 0;
}

测试它live on Coliru

使用 gcc 的错误

main.cpp: 在函数 'unsigned int f(std::integer_sequence) [无符号整数 ...I = {}]':

main.cpp:17:18: 错误:无法转换 'std::make_integer_sequence{}' 来自 'integer_sequence' 到 'integer_sequence'

用 clang++ 报告了类似的转换错误

错误:没有来自'std::make_integer_sequence' (又名 '__make_integer_seq') 到 'std::integer_sequence'

然而,奇怪的是,如果我删除认参数,并将相同的表达式传递给 f,程序会编译并给出更正后的输出

#include <utility>
#include <iostream>

#define N 4

template <unsigned int I>
unsigned int g() { return I; }

template <unsigned int... I>
unsigned int f(std::integer_sequence<unsigned int,I...>)
{
  return (g<I>() + ...);
}

int main()
{
  std::cout << f(std::make_integer_sequence<unsigned int,N>{}) << std::endl;
  return 0;
}

live on Coliru

一个代码有什么问题/区别?

解决方法

我承认,我不明白错误信息。第二个版本编译而不是第一个版本编译的原因是模板参数不能从默认参数中推导出来,而是从函数参数中推导出来。考虑这个更简单的例子:

#include <utility>
#include <iostream>

template <unsigned int>
struct foo {};

template <unsigned int x>
foo<x> make_foo(){ return {};}

template <unsigned int x>
unsigned int f(foo<x> = make_foo<4>())
{
  return 42;
}

int main()
{
  std::cout << f() << std::endl;
  return 0;
}

这里的错误更具描述性:

<source>: In function 'int main()':
<source>:18:18: error: no matching function for call to 'f()'
   18 |   std::cout << f() << std::endl;
      |                  ^
<source>:11:14: note: candidate: 'template<unsigned int x> unsigned int f(foo<x>)'
   11 | unsigned int f(foo<x> = make_foo<4>())
      |              ^
<source>:11:14: note:   template argument deduction/substitution failed:
<source>:18:18: note:   couldn't deduce template parameter 'x'
   18 |   std::cout << f() << std::endl;
      |                  ^

make_integer_sequence<unsigned int,N> 的主要目的是像您在第二个示例中所做的那样,从单个 N 过渡到 std::integer_sequence<unsigned int,I...> 中的包。

通过间接级别,您可以避免调用者必须传递参数:

// ...

template <unsigned int... I>
unsigned int f(std::integer_sequence<unsigned int,I...>)
{
  return (g<I>() + ...);
}

template <unsigned int X = N>
unsigned int f_wrap()
{
  return f(std::make_integer_sequence<unsigned int,N>{});
}

int main()
{
  std::cout << f_wrap() << std::endl;
  return 0;
}

Live Demo

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...