I have a struct:
typedef struct
{
int nNum;
string str;
}KeyPair;
Let's say I initialize my struct:
KeyPair keys[] =
{ {0, "tester"},
{2, "yadah"},
{0, "tester"}
};
I want to use the initialized values in a function. How do I pass this array struct as a function parameter?
I have:
FetchKeys( KeyPair *pKeys)
{
//get the contents of keys[] here...
}
How about?
template<int N> void FetchKeys(KeyPair const (&r)[N]){}
EDIT 2:
Or even
template<int N> void FetchKeys(KeyPair const (*p)[N])
with the call as
FetchKeys(&keys);
You can do it as #MSalters mentioned, or you can create a std::vector<KeyPair> and pass it to the function. Here is a sample code:
using namespace std;
struct KeyPair
{
int nNum;
string str;
};
void fetchKeys(const vector<KeyPair>& keys)
{
//Go through elements of the vector
vector<KeyPair>::const_iterator iter = keys.begin();
for(; iter != keys.end(); ++iter)
{
const KeyPair& pair = *iter;
}
}
int main()
{
KeyPair keys[] = {{0, "tester"},
{2, "yadah"},
{0, "tester"}
};
//Create a vector out of the array you are having
vector<KeyPair> v(keys, keys + sizeof(keys)/sizeof(keys[0]));
//Pass this vector to the function. This is safe as vector knows
//how many element it contains
fetchKeys(v);
return 0;
}
Should be
// Definition
void FetchKeys( KeyPair *pKeys, int nKeys)
{
//get the contents of keys[] here...
}
// Call
FetchKeys(keys, sizeof(keys)/sizeof(keys[0]));
In c/c++ the name of the array (of any type) represents the address of the first element of the array, so
keys and &keys [0] are same.
You can pass any one of them for KeyPair*.
You just callFetchKeys(keys);
EDIT
Pay attention to declare FetchKeys' return type.
EDIT 2
If you also need the number of items, you add size as FetchKeys input parameters:
void FetchKeys(KeyPair*, size_t size);
and call FetchKeys(keys, sizeof(keys)/sizeof(*keys));
BTW, state all your question by editing your first post if you can.
Depending on what you want to do you can even use boost range and pass it to function as a pair of iterators:
void FetchKeys(KeyPair *begin, KeyPair *end)
FetchKeys(boost::begin(keys), boost::end(keys));
See this answer: How can I pass an array by reference to a function in C++?
Wrap it in a structure, nice and easy..
#include <iostream>
struct foo
{
int a;
int b;
};
template <typename _T, size_t _size>
struct array_of
{
static size_t size() { return _size; }
_T data[_size];
};
template <typename _at>
void test(_at & array)
{
cout << "size: " << _at::size() << std::endl;
}
int main(void)
{
array_of<foo, 3> a = {{ {1,2}, {2,2}, {3,2} }};
test(a);
}
EDIT: URGH, I can't see the toolbar to format the code correctly, hopefully the tags works..
i use VS 2008, and this works fine for me.
#include "stdafx.h"
typedef struct
{
int nNum;
CString str;
}KeyPair;
void FetchKeys( KeyPair *pKeys);
int _tmain(int argc, _TCHAR* argv[])
{
KeyPair keys[] =
{ {0, _T("tester")},
{2, _T("yadah")},
{0, _T("tester")}
};
FetchKeys(keys); //--> just pass the initialized variable.
return 0;
}
void FetchKeys(KeyPair *pKeys)
{
printf("%d, %s\n",pKeys[0].nNum, pKeys[0].str);
}
I don't understand the difficulty. correct me if i'm wrong. To keep it simple, i avoided using vectors, templates and etc.
edit: to know size of struct, you can pass one more arg.
Related
I have a static array in a class and an enum for the index of such array.
enum MyEnum
{
FIRST = 0,
SECOND,
LAST
}
class MyClass
{
public:
static string names[LAST];
}
I'd like to initialize my static array to associate a value of the array to each enum type like this:
names[FIRST] = "First";
names[SECOND] = "Second";
I know that I can initialize the array upon declaration like this static string names[] = {"First", "Second"}, but I want to explicitly assign the value to the corresponding enum to avoid errors.
In Java, there's a static block where you can do this kind of initialization, but I don't think that this is the case in C++. Is there an elegant way of doing this? I can't use std on my project, so the solution has to avoid any library usage.
Thanks in advance.
Write a function to initialize it. Function can't return an array - if you want to use an array, return a whole object that has an array inside it. Or you can return something dynamically allocated, a map or a vector.
#include <array>
#include <string>
enum MyEnum {
FIRST = 0,
SECOND,
LAST
};
std::array<std::string, LAST> construct_names() {
std::array<std::string, LAST> r;
r[FIRST] = "first";
r[SECOND] = "second";
return r;
}
static auto names = construct_names();
I can't use std on my project, so the solution has to avoid any library usage.
Roll your own types.
enum MyEnum {
FIRST = 0,
SECOND,
LAST
};
template<typename T, unsigned N>
struct MyArray {
T data[N];
T &operator[](unsigned i) {
return data[i];
}
};
MyArray<const char *, LAST> construct_names() {
MyArray<const char *, LAST> r;
r[FIRST] = "first";
r[SECOND] = "second";
return r;
}
static auto names = construct_names();
You may also want to read How to initialize private static members in C++? or similar, as for class initialization you need to do like, there will be some type repetition:
class MyClass {
public:
static MyArray<const char *, LAST> names;
};
MyArray<const char *, LAST> MyClass::names = construct_names();
Yes you can do it in simple way using __attribute__((init_priority(101))) and __attribute__((constructor(102)))
#include <string>
#include <iostream>
using namespace std;
enum MyEnum
{
FIRST = 0,
SECOND,
LAST
};
class MyClass
{
public:
static string names[LAST];
};
__attribute__((init_priority(101))) string MyClass::names[LAST];
__attribute__((constructor(102))) void foo()
{
MyClass::names[FIRST] = "First";
MyClass::names[SECOND] = "Second";
}
int main()
{
MyClass m;
for (int i = 0; i < LAST; i++) {
cout << m.names[i] << "\n";
}
}
Output:
First
Second
Explanation in simple:
Before even code loads, first it initialize string MyClass::names[LAST]; because we added __attribute__((init_priority(101))) then it calls foo() automatically, The function name can be any it does not matter, it can be init as well no need to be foo. The order of initialization is based on number 101 and 102. If we change the order then it wont work.
For more info refer: https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#index-init_005fpriority-variable-attribute
Declaimer: This initialization is not bound to the class, if you keep on adding like this for all the classes then you are in big trouble and you need to keep on maintain a list of orders. This inits are for the entire binary or library
The following snippet of code simply creates a structure that has three members. One of them is a callback function. I would like to initialize an array of these structures but I don't know the syntax, where I can have multiple callbacks with varying prototypes.
#include <iostream>
#include <functional>
template <typename Func>
struct Foo
{
Foo(int a, int b, Func func):
_a{a},
_b{b},
_func{func}{}
int _a;
int _b;
Func _func;
};
int main() {
auto test = [](){std::cout << "hello\n";};
Foo<std::function<void(void)>> foo(5,10, test);
foo._func();
//array version
//......................
}
How about this
//array version
Foo<std::function<void(void)>> a[] = { {5, 10, test}, {1, 2, test} };
Depending on what "array" you want to use, I think the creation is straight-forward, here with std::vector. You can use any container you like. Accessing here done with [], but could also be done with the at() method
typedef Foo<std::function<void(void)>> FooTypeDef;
int main() {
auto test = [](){std::cout << "hello\n";};
FooTypeDef foo(5,10, test);
foo._func();
//array version
//......................
std::vector<FooTypeDef> array;
array.push_back(foo);
array.push_back(foo);
array[0]._func();
array[1]._func();
}
And maybe use a typedef ;)
i need a way to initialize const elements of an array for the program i am currently working on.
The problem is that i have to initialize these elements with a function, there is no way to do it like this:
const int array[255] = {1, 1278632, 188, ...};
because its alot of data i have to generate.
What i tried is to memcpy data to the const int's but that can't work and hasn't worked.
const int array[255];
void generateData(){
for(int i = 0; i < 255; i++) {
initializeSomehowTo(5, array[i]);
}
}
I hope you understand what i am trying, sorry if i doubled the question, i must have overlooked it.
How about this?
#include <array>
typedef std::array<int, 255> Array;
const Array array = generateData();
Array generateData(){
Array a;
for(int i = 0; i < a.size(); i++) {
initializeSomehowTo(a[i]);
}
return a;
}
The easiest approach is to get the filled array from a function and use that to initialize your const (or constexpr) object. However, built-in arrays can't be copied but std::array<T, N> be:
std::array<T, 255> array = initializeData();
If you need a built-in array, I can imagine initializing a static member of a class (template, actually) where the index is expanded from indices expanded from an std::make_index_sequence<255> and used as positional argument in the array, i.e., something along these lines:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <utility>
int some_function(std::size_t i) { return i; }
template <typename> struct initialized_array_base;
template <std::size_t... I>
struct initialized_array_base<std::index_sequence<I...>> {
static const int array[sizeof...(I)];
};
template <std::size_t... I>
int const initialized_array_base<std::index_sequence<I...>>::array[sizeof...(I)]
= { some_function(I)... };
struct initialized_array
:initialized_array_base<std::make_index_sequence<256>> {
};
int main() {
std::copy(std::begin(initialized_array::array),
std::end(initialized_array::array),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}
You can create a writable array, initialize it, and, then, create a const reference to it.
int arry[255];
void generateData(){
for(int i = 0; i < 255; i++) {
initializeSomehowTo(5, arry[i]);
}
}
const int (&array)[255] = arry;
As we know in c++, we can reinitialize an array arr of size N with a value 0 as,
fill (arr, arr + N, 0);
But I need to reinitialize the array with a struct S,
struct S {
int b[2];
}
The actual code is,
#include <iostream>
using namespace std;
struct Dog
{
int count[2];
};
int main(){
...
Dog dogs[N];
...
while (T--)
{
...
for (int i = 0; i < M; ++i)
{
fill(dogs, dogs+N, {0});
...
}
...
}
}
For the case:
struct Dog { int count[2]; };
Dog dogs[N];
you can use:
std::fill(dogs, dogs+N, Dog{});
The third argument to fill must have the right type already, the compiler does not deduce the type from the iterator. So you cannot just use {} or {0}.
Consider using std::begin(dogs), std::end(dogs) instead of dogs, dog+N as that removes the possibility of using the wrong value for N.
I'm not sure why fill was designed this way, as it is certainly possible to write a function which does accept initializer list as well as normal values:
#include <algorithm>
template<typename It>
void mfill(It begin, It end, typename std::remove_reference<decltype(*begin)>::type const &v)
{
std::fill(begin, end, v);
}
struct Dog { int count[2]; };
int main()
{
Dog dogs[5];
mfill(dogs, dogs+5, {});
}
You can use fill_n as follows:
struct Dog
{
int count[2];
};
int main(){
Dog dogs[4] = {};
dogs[0].count[0] = 1;
std::fill_n(dogs, 0, Dog{});
}
Since Dog is a pod structure, you can default construct it in the last parameter of fill_n
I'm doing a programming question from C++ Primer Plus which asks me to make a template
function that returns the number of unique elements in an array. I don't understand why
line 13 causes an error while compiling as to my knowledge, a std::string behaves like an array.
This is my code:
#include <iostream>
#include <set>
template <typename T>
int reduce(T ar[], int n);
int main()
{
long test[] = {1, 2, 1, 3, 3, 4, 1};
std::string testStr = "testing";
std::cout << reduce(test, 6) << std::endl;
std::cout << reduce(testStr, 7) << std::endl;
std::cin.get();
return 0;
}
template <typename T>
int reduce(T ar[], int n)
{
std::set<T> test;
for(int i = 0; i < n; i++)
{
test.insert(ar[i]);
}
return test.size();
}
Following up my immediate response that std::string is not an array, this is the way a C++ person might accomplish the task you're looking for.
#include <iterator>
#include <iostream>
#include <set>
// instead of taking an array and length, just take where you want to start and where
// you want to stop.
template <typename TForwardIterator>
int reduce(TForwardIterator iter, TForwardIterator end)
{
// This is hideous syntax to get the type of object the iterator is describing.
// For std::string, it is char...for T*, it is T.
// I apologize for C++, I'm not sure there is a better way to do this.
typedef typename std::iterator_traits<TForwardIterator>::value_type value_type;
std::set<value_type> set;
// instead of forcing the objects to be an array type, use iterators!
for (; iter != end; ++iter)
set.insert(*iter);
return set.size();
}
int main()
{
long test[] = {1, 2, 1, 3, 3, 4, 1};
std::string testStr = "testing";
// begin() and end() are iterators you'll find on all the container types
std::cout << reduce(testStr.begin(), testStr.end()) << std::endl;
// pointers are iterators, too!
std::cout << reduce(test, test + 7) << std::endl;
return 0;
}
The answer is quite simple: std::string is not an array.
It behaves like an array so far as you can access the elements using the [] operator, but it is simply not the same data type as char[]. As a matter of fact the standard doesn't even guarantee that it's stored like an array (meaning continously). T[] will only match to array of, not objects which can be used arraylike.
In order to solve this you have several options
you can call reduce(teststr.c_str(), 7), since c_str() will return an chararray with the contents of the string.
You could rewrite reduce as template <typename T, typename U> int reduce(U ar, int n) and call it as reduce<long>(test, 6) and reduce<char>(testStr, 7). The second template parameter is necessary, since there is no unified way to get from the container to the element (except in c++0x/using compiler extensions).
If you are using c++0x you can use decltype to get from a container to the contained element: template <typename T>int reduce(T ar, int n) and std::set<decltype(ar[0])> test; (rest of the code remains unchanged, and somehow I seem to have trouble with code block sections so just these two lines here.
Of course in c++ one would typically write such a function in terms of iterators (see Travis Gockels answer), since that's simply a more flexible and better supported way.
You may be confusing std::strings with built-in character arrays. std::strings are not arrays, though they behave similarly to arrays (the class has an overloaded [] operator) and contain arrays (which you can access through c_str()).
If you replace line 10 with
char testStr[] = "testing";
Your program will compile and run.
Or, you could try something like:
#include <iostream>
#include <set>
template <typename T>
int reduce(const T* ar, int n);
int main()
{
long test[] = {1, 2, 1, 3, 3, 4, 1};
std::string testStr = "testing";
std::cout << reduce(test, 7) << std::endl;
std::cout << reduce(testStr.c_str(), testStr.size()) << std::endl;
std::cin.get();
return 0;
}
template <typename T>
int reduce (const T* ar, int n)
{
std::set<T> test;
for(int i = 0; i < n; i++)
{
test.insert(ar[i]);
}
return test.size();
}