如何传递临时数组?

时间:2017-02-19 20:03:54

标签: c++ arrays reference parameter-passing temporary

如何传递临时数组?我想做这样的事情:

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

我是否需要在函数参数&#39;大括号[]中使用正整数文字?如果我包含该文字,它会限制我可以传递给那个大小的数组的数组吗?另外,如何通过rvalue引用或const引用传递数组元素?由于上面的示例没有编译,我认为函数的参数类型int&&[]const int&[]不会起作用。

2 个答案:

答案 0 :(得分:11)

首先,您不能传递数组作为prvalues,因此您的函数需要参考。其次,数组的大小是类型的一部分,因此您的函数可能需要成为模板的一部分。第三,编写数组临时工具在词汇上有点傻,所以你需要一些噪音。

总而言之,以下应该有效

template <std::size_t N>
int sum(const int (&a)[N])
{
    int n = 0;
    for (int i : a) n += i;
    return 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})(您无法从初始化程序中推断出模板参数。)

答案 1 :(得分:1)

我建议将sum函数设置为接受任何范围的模板,而不是将其限制为数组。这样你就可以使用标准容器的函数,比如std :: vector,std :: set甚至是用户定义的容器。

我的解决方案需要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作为返回类型只是为了使函数声明更具可读性。你也可以这样写:

    typename boost::range_value< Range >::type sum( const Range& range )

  • boost::range_value模板用于推断范围元素的类型。这样我们就可以将sum()不仅用于整数,而且还可以使用operator +=定义的任何东西!您可以在我的示例中看到我们甚至可以添加&#34; (连接)字符串在一起。 :d

  • 最后使用std::initializer_list参数的重载使得简单的语法成为可能,我们可以根据OP的请求调用sum({ 1, 2, 3 })。此重载是必需的,因为泛型重载不会推断出initializer_list参数类型(另请参阅initializer_list and template type deduction

<强>演示:

http://coliru.stacked-crooked.com/a/80393e710fc355a6