如何传递临时数组?
How to pass a temporary array?
如何传递临时数组?我想做这样的事情:
#include <iostream>
int sum(int arr[]) {
int answer = 0;
for (const auto& i : arr) {
answer += i;
}
return answer;
}
int main() {
std::cout << sum( {4, 2} ) << std::endl; // error
std::cout << sum( int[]{4, 2} ) << std::endl; // error
}
函数参数的大括号中是否需要正整数文字 []
?如果我包含该文字,它是否会限制我只能传递给该大小的数组的数组?另外,如何通过右值引用或 const 引用传递数组元素?因为上面的示例没有编译,我假设函数的参数类型 int&&[]
或 const int&[]
将不起作用。
首先,你不能传递数组作为纯右值,所以你的函数需要引用。其次,数组的大小是类型的一部分,因此您的函数可能需要成为模板的一部分。 第三,写临时数组在词汇上有点傻,所以你需要一些噪音。
综上所述,以下应该可行
template <std::size_t N>
int sum(const int (&a)[N])
{
int n = 0;
for (int i : a) n += i;
return n;
}
int main()
{
std::cout << sum({1, 2, 3}) << "\n";
}
int main()
{
using X = int[3];
std::cout << sum(X{1, 2, 3}) << "\n";
}
可以使用别名模板稍微概括句法噪音:
template <std::size_t N> using X = int[N];
用法:sum(X<4>{1, 2, 3, 4})
(您不能从初始值设定项中推导出模板参数。) 编辑: 感谢 Jarod42 指出它实际上完全有可能从花括号列表中推导出模板参数;不需要类型别名。
我建议使 sum 函数成为接受任何 range 的模板,而不是将其限制为数组。这样您就可以将函数与标准容器一起使用,例如 std::vector、std::set 甚至 user-defined 容器。
我的解决方案需要 boost.range 库,但今天谁没有使用 boost?范围甚至被认为被添加到标准库中。
#include <iostream>
#include <array>
#include <vector>
#include <string>
#include <boost/range.hpp>
#include <initializer_list>
template< typename Range >
auto sum_impl( const Range& range ) -> typename boost::range_value< Range >::type
{
typename boost::range_value< Range >::type result{};
for( const auto& elem : range )
result += elem;
return result;
}
template< typename Range >
auto sum( const Range& range ) -> typename boost::range_value< Range >::type
{
return sum_impl( range );
}
template< typename Elem >
Elem sum( const std::initializer_list< Elem >& range )
{
return sum_impl( range );
}
int main()
{
// Call the initializer_list overload
std::cout << sum( { 1, 2, 3 } ) << "\n";
std::cout << sum( { 1.0f, 2.1f, 3.2f } ) << "\n";
// Call the generic range overload
std::cout << sum( std::array<int,3>{ 1, 2, 3 } ) << "\n";
std::cout << sum( std::vector<float>{ 1.0f, 2.1f, 3.2f } ) << "\n";
std::cout << sum( std::vector<std::string>{ "a", "b", "c" } ) << "\n";
}
一些解释:
我使用 auto
作为 return 类型只是为了使函数声明更具可读性。你也可以这样写:
typename boost::range_value< Range >::type sum( const Range& range )
boost::range_value
模板用于推断范围元素的类型。这样我们不仅可以将 sum() 用于整数,还可以用于任何定义了 operator +=
的东西!您可以在我的示例中看到,我们甚至可以 "add" (连接)字符串在一起。 :D
采用 std::initializer_list
参数的重载最终使我们可以按照 OP 的要求调用 sum({ 1, 2, 3 })
的简单语法成为可能。此重载是必需的,因为通用重载不会推断 initializer_list 参数类型(另请参阅 initializer_list and template type deduction )
演示:
如何传递临时数组?我想做这样的事情:
#include <iostream>
int sum(int arr[]) {
int answer = 0;
for (const auto& i : arr) {
answer += i;
}
return answer;
}
int main() {
std::cout << sum( {4, 2} ) << std::endl; // error
std::cout << sum( int[]{4, 2} ) << std::endl; // error
}
函数参数的大括号中是否需要正整数文字 []
?如果我包含该文字,它是否会限制我只能传递给该大小的数组的数组?另外,如何通过右值引用或 const 引用传递数组元素?因为上面的示例没有编译,我假设函数的参数类型 int&&[]
或 const int&[]
将不起作用。
首先,你不能传递数组作为纯右值,所以你的函数需要引用。其次,数组的大小是类型的一部分,因此您的函数可能需要成为模板的一部分。 第三,写临时数组在词汇上有点傻,所以你需要一些噪音。
综上所述,以下应该可行
template <std::size_t N>
int sum(const int (&a)[N])
{
int n = 0;
for (int i : a) n += i;
return n;
}
int main()
{
std::cout << sum({1, 2, 3}) << "\n";
}
int main()
{
using X = int[3];
std::cout << sum(X{1, 2, 3}) << "\n";
}
可以使用别名模板稍微概括句法噪音:
template <std::size_t N> using X = int[N];
用法:sum(X<4>{1, 2, 3, 4})
(您不能从初始值设定项中推导出模板参数。) 编辑: 感谢 Jarod42 指出它实际上完全有可能从花括号列表中推导出模板参数;不需要类型别名。
我建议使 sum 函数成为接受任何 range 的模板,而不是将其限制为数组。这样您就可以将函数与标准容器一起使用,例如 std::vector、std::set 甚至 user-defined 容器。
我的解决方案需要 boost.range 库,但今天谁没有使用 boost?范围甚至被认为被添加到标准库中。
#include <iostream>
#include <array>
#include <vector>
#include <string>
#include <boost/range.hpp>
#include <initializer_list>
template< typename Range >
auto sum_impl( const Range& range ) -> typename boost::range_value< Range >::type
{
typename boost::range_value< Range >::type result{};
for( const auto& elem : range )
result += elem;
return result;
}
template< typename Range >
auto sum( const Range& range ) -> typename boost::range_value< Range >::type
{
return sum_impl( range );
}
template< typename Elem >
Elem sum( const std::initializer_list< Elem >& range )
{
return sum_impl( range );
}
int main()
{
// Call the initializer_list overload
std::cout << sum( { 1, 2, 3 } ) << "\n";
std::cout << sum( { 1.0f, 2.1f, 3.2f } ) << "\n";
// Call the generic range overload
std::cout << sum( std::array<int,3>{ 1, 2, 3 } ) << "\n";
std::cout << sum( std::vector<float>{ 1.0f, 2.1f, 3.2f } ) << "\n";
std::cout << sum( std::vector<std::string>{ "a", "b", "c" } ) << "\n";
}
一些解释:
我使用
auto
作为 return 类型只是为了使函数声明更具可读性。你也可以这样写:typename boost::range_value< Range >::type sum( const Range& range )
boost::range_value
模板用于推断范围元素的类型。这样我们不仅可以将 sum() 用于整数,还可以用于任何定义了operator +=
的东西!您可以在我的示例中看到,我们甚至可以 "add" (连接)字符串在一起。 :D采用
std::initializer_list
参数的重载最终使我们可以按照 OP 的要求调用sum({ 1, 2, 3 })
的简单语法成为可能。此重载是必需的,因为通用重载不会推断 initializer_list 参数类型(另请参阅 initializer_list and template type deduction )
演示: