How to pass a temporary array?

前端 未结 2 1184
夕颜
夕颜 2020-12-07 01:38

How can I pass a temporary array? I want to do something like this:

#include 

int sum(int arr[]) {
    int answer = 0;
    for (const auto&a         


        
相关标签:
2条回答
  • 2020-12-07 01:55

    First off, you cannot pass arrays as prvalues, so your function needs to take a reference. Second, the size of the array is part of the type, so your function probably needs to be part of a template. Third, writing array temporaries is lexically a bit silly, so you need some noise.

    Putting it all together, the following ought to work

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

    The syntactic noise can be generalized slightly with an alias template:

    template <std::size_t N> using X = int[N];
    

    Usage: sum(X<4>{1, 2, 3, 4}) (You cannot have the template parameter deduced from the initializer.) Edit: Thanks to Jarod42 for pointing out that it is in fact perfectly possible to deduce the template argument from a braced list; no type alias is needed.

    0 讨论(0)
  • 2020-12-07 02:07

    I suggest making the sum function a template that accepts any range instead of limiting it to arrays. This way you could use the function with standard containers like std::vector, std::set or even user-defined containers too.

    My solution requires the boost.range library but who isn't using boost today? Ranges are even considered to be added to the standard library.

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

    Some explanations:

    • I'm using auto as return type just to make the function declaration more readable. You could also write it like this:

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

    • The boost::range_value template is used to deduce the type of the elements of the range. This way we can use sum() not only for ints, but anything that has an operator += defined! You can see in my example that we can even "add" (concatenate) strings together. :D

    • The overload taking a std::initializer_list parameter finally makes the easy syntax possible where we can call sum({ 1, 2, 3 }) as requested by the OP. This overload is required because the generic overload won't deduce the initializer_list argument type (see also initializer_list and template type deduction )

    Demo:

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

    0 讨论(0)
提交回复
热议问题