有没有办法在 C++ 中将匿名数组作为参数传递?

问题描述 投票:0回答:15

我希望能够在 C++ 中将数组声明为函数参数,如下面的示例代码所示(无法编译)。 有什么方法可以做到这一点(除了事先单独声明数组之外)?

#include <stdio.h>

static void PrintArray(int arrayLen, const int * array)
{
   for (int i=0; i<arrayLen; i++) printf("%i -> %i\n", i, array[i]);
}

int main(int, char **)
{
   PrintArray(5, {5,6,7,8,9} );  // doesn't compile
   return 0;
}
c++ arrays arguments
15个回答
39
投票

如果您使用的是较旧的 C++ 变体(C++0x 之前的版本),则这是不允许的。您所指的“匿名数组”实际上是一个初始化列表。现在 C++11 已经出来了,这可以使用内置的

initializer_list
类型来完成。理论上,您还可以使用
extern C
将其用作 C 样式初始化列表,如果您的编译器将它们解析为 C99 或更高版本

例如:

int main()
{
    const int* p;
    p = (const int[]){1, 2, 3};
}

33
投票

在 C++11 和

extern "C"
中允许使用 C99 进行类型转换:

void PrintArray(size_t len, const int *array)
{
    for(size_t i = 0; i < len; i++)
        printf("%d\n", array[i]);
}

int main(int argc, char **argv)
{
    PrintArray(5, (const int[]){1, 2, 3, 4, 5});
    return 0;
}

19
投票

这个可以编译,但我不推荐它。

#include <stdio.h>

struct arr
{
   int array[5];
};

static void PrintArray(int arrayLen, arr array)
{
   for (int i=0; i<arrayLen; i++) printf("%i -> %i\n", i, array.array[i]);
}

int main(int, char **)
{
   PrintArray(5, (arr){5,6,7,8,9});
   return 0;
}

9
投票

免责声明:对于这个答案,我得到了一些反对票,但它起源于 2009 年,当时 C++ 11 即将被定义。对于现代 C++,请滚动到下面。

好吧,尝试使用 boost...

这里是使用 boost::assign 库和更多 C++ 编程的解决方案;)

#include <boost/assign/list_of.hpp>

#include <iostream>
#include <algorithm>


namespace
{
  template<class CollectionT>
  void print(CollectionT const& coll)
  {
    std::ostream_iterator<int> out(std::cout, ", ");
    std::copy(coll.begin(), coll.end(), out);
  }
}



int main()
{
  using namespace boost::assign;

  print( list_of(1)(2)(3)(4)(5) );

  return 0;
}

C++ 11 及更高版本以及特定功能的解释

遵守 clang:

clang++ -std=c++14 -I /usr/local/include/ main.cpp

#include <boost/assign/list_of.hpp>

#include <iostream>
#include <iterator>
#include <algorithm>
#include <initializer_list>


template<typename CollectionT, typename OStream>
auto // <- auto result type deduction from C++ 14
  make_output_iterator(CollectionT const& coll, OStream& out)
{
  return std::ostream_iterator<typename CollectionT::value_type>(out, ", ");
}

// here template specialization is used, to demonstrate initializer lists from C++ 11
template<typename T>
void print(std::initializer_list<T> items)
//         ^----------------------^ passed by value due to move semantics
{
  using namespace std;
  cout << "printing an initializer list: ";
  copy(items.begin(), items.end(), make_output_iterator(items, cout));
  cout << endl;
}


template<typename CollectionT>
void print(CollectionT const& items)
{
  using namespace std;
  cout << "printing another collection type: ";
  copy(items.begin(), items.end(), make_output_iterator(items, cout));
  cout << endl;
}


int main()
{
  print({0,1,2,3,4,5,6,7,9});

  using namespace boost::assign;
  print( list_of(0)(1)(2)(3)(4)(5)(6)(7)(8)(9) );
}

8
投票

从C++11开始,你可以直接使用

std::begin(std::initializer_list const&)
来获取指针。示例:

#include <iostream>
#include <iterator>
void func(int len, const int* x)
{
    for(int i=0;i<len;++i)
        std::cout << x[i] << "\n";
}
int main()
{
    func(5, std::begin({1,3,6,823,-35}));
}

与接受的答案不同,这确实是标准兼容的代码。


5
投票

使用 C++0x,您可以使用

std::initializer_list
(和 foreach 循环)

#include <iostream>
#include <initializer_list>

void print (const std::initializer_list<int>& array)
{
    for (auto x : array) // C++0x foreach loop
        std::cout << x << std::endl;
}

int main (int argc, char ** argv)
{
    print ({ 1, 2, 3, 4, 5 });
}


4
投票

是和不是。在标准的当前版本(ISO C++ 1998 以及 2003 年的修订)中,这是不可能的。然而,在标准“C++0x”的下一个版本中(尽管其名称暗示它将在 200x 中发布,但很可能会在 2010 年发布),可以使用 std::initializer_list<> .


3
投票

您可以使用 Joe D 建议的 std::initializer_list list ,但是我不确定如果您需要其他参数是否可以使用它。 (我似乎找不到任何相关信息。)但是,如果您声明对向量的 const 引用,则使用 { ... } 创建的初始化器列表将转换为向量。

#include <iostream>
#include <vector>

void PrintArray(const char* prefix, const std::vector<int>& array)
{
    std::cout << prefix << std::endl;
    for (int i : array) {
        std::cout << i << std::endl;
    }
}

int main(int, char **)
{
    PrintArray("test array", {5,6,7,8,9} );
    return 0;
}

2
投票

您可以使用可变数量的参数而不是传递数组:

static void PrintArray(int arrayLen, ...)
{
   int this_value;
   va_list array;

   va_start(array, arrayLen);
   for (int i=0; i<arrayLen; i++) 
   {
     this_value = va_arg(array, int);
     printf("%i -> %i\n", i, this_value);
   }
   va_end(array);
}

我没有编译这个,所以我可能犯了一两个错误,但希望它足够接近。 查找 va_start 以供参考。


2
投票

这是一个简单干净的解决方案,用于获取其他人没有提到过的 C 样式数组:

#include <iostream>

using namespace std;

template <int N>
int
get_last( const int ( &my_array )[N] ) {
  return my_array[N-1];
}


int main()
{
    cout << "Last: " << get_last( { 1, 2, 3, 55 } );

    return 0;
}

1
投票

另一种选择是使用 TR1 库中的数组,它很可能成为下一个标准的一部分,并受到许多编译器的支持。

#include <array>
#include <algorithm>
#include <iostream>

using std::tr1::array;
using std::cout;
using std::copy;
using std::ostream_iterator;

template <class Container>
void PrintArray(Container &values)
{
  copy(values.begin(), values.end(), ostream_iterator<int>(cout, "\n"));
}

int main()
{
  array<int, 5> values = {1, 2, 3, 4, 5};
  PrintArray(values);
}

1
投票

您可以在 ANSI-C 中使用良好的 ol' va_list

来完成此操作

为了方便起见,还返回了模板化 C++

std::vector

#include <stdarg.h>
#include <vector>
using namespace std ;

struct Point
{
  int x,y;
  Point():x(0),y(0){}
  Point( int ix, int iy ):x(ix),y(iy){}
  ~Point(){printf("%d %d - the point has been destroyed!\n",x,y);}
  void print(){printf("%d,%d\n",x,y);}
} ;

// Concrete example using a list of int
int* initFrom( int numItems, ... )
{
  int* list = new int[ numItems ] ;

  va_list listPointer;
  va_start( listPointer, numItems );

  for( int i = 0 ; i < numItems; i++ )
    list[ i ] = va_arg( listPointer, int ) ;

  return list ;
}

// templatized version.
template <typename T> vector<T> initFrom( int numItems, ... )
{
  vector<T> list ;
  list.resize( numItems ) ;

  va_list listPointer;
  va_start( listPointer, numItems );

  for( int i = 0 ; i < numItems; i++ )
    list[ i ] = va_arg( listPointer, T ) ;

  return list ;
}

int main()
{
  int* theList = initFrom( 4, 900, 2000, 1000, 100 ) ;
  for( int i = 0 ; i < 4 ; i++ )
    printf( "Item %d=%d\n", i, theList[i] );

  puts( "\n\n--Lots of destruction using non-ptr" ) ;
  vector<Point> thePoints = initFrom<Point>( 3, Point(3,7), Point(4,5), Point(99,99) ) ;
  puts( "Our listing:" ) ;
  for( int i = 0 ; i < 3 ; i++ )
    thePoints[i].print() ;

  puts( "\n\n-- Less destruction using ptr" ) ;
  // Be careful of extra copy construction. Using a vector of pointers
  // will avoid that
  vector<Point*> theNewPoints = initFrom<Point*>( 3, new Point(300,700), new Point(400,500), new Point(990,990) ) ;
  puts( "Our listing:" ) ;
  for( int i = 0 ; i < 3 ; i++ )
    theNewPoints[i]->print() ;

  puts( "END OF PROGRAM --" ) ;
}

0
投票

PrintArray
函数期待
int*
,但是
const
。因此,您可以传递使用
int
创建的临时
new
数组。

PrintArray(5, new int[5]{5,6,7,8,9});

或与

std::move()
一起添加更多感觉。

#include <utility>
PrintArray(5, std::move(new int[5]{5,6,7,8,9}));

0
投票

如果你有哨兵,你可以使用C的stdarg.h而不带计数,在使用字符串时尤其自然:

#include <stdio.h>
#include <stdarg.h>

void printStrings (const char *s1, ...)
{
    va_list ap;
    va_start (ap, s1);
    const char *s = s1;
    while (s) {
        printf ("%s\n", s);
        s = va_arg (ap, char *);
    }
    va_end (ap);
}

int main (int ac, char *av[])
{
    printStrings ("hello", "world", NULL);
    return 0;
}

-4
投票

不,无论如何,这都是不好的编码习惯。只需在函数调用之前声明

const int* foo = {5,6,7,8,9};
即可。即使这确实有效,它也不会加快你的程序或编译时间。这些值仍然需要在内存中分配并通过函数调用传递。

© www.soinside.com 2019 - 2024. All rights reserved.