I want to use std::copy to copy an existing array of structures to new one. A regular option is fine with '''local_copy()'''. I want to know the procedure to use std::copy for such case described below -
I tried the code and get following error at compile time
#include <iostream>
class BigClass{
public:
struct Astruct{
double x[2], v[2];
int rank;
}one_struct;
};
void allocate(struct BigClass::Astruct& one_struct, int i)
{
one_struct.x[0] = 1.1;
one_struct.x[1] = 1.2;
one_struct.v[0] = 2.1;
one_struct.v[1] = 2.2;
one_struct.rank = i;
}
void local_copy(struct BigClass::Astruct& dest, struct BigClass::Astruct& source)
{
dest.x[0] = source.x[0];
dest.x[1] = source.x[1];
dest.v[0] = source.v[0];
dest.v[1] = source.v[1];
dest.rank = source.rank;
}
void print(struct BigClass::Astruct one_struct)
{
std::cout << one_struct.rank << " " << one_struct.x[0] << " " << one_struct.x[1] << " " << one_struct.v[0] << " " << one_struct.v[1] << "\n";
}
int main(int argc, char *argv[]) {
int size = 10;
struct BigClass::Astruct BCobj[size];
for(int i = 0; i < size; i++) allocate(BCobj[i], i);
for(int i = 0; i < size; i++) print(BCobj[i]);
struct BigClass::Astruct second_BCobj[size];
//for(int i = 0; i < size; i++) local_copy(second_BCobj[i], BCobj[i]); // this works
for(int i = 0; i < size; i++) std::copy(BCobj[i+1], BCobj[i], second_BCobj[i]); // not working
for(int i = 0; i < size; i++) print(BCobj[i]);
}
The compile time error is following -
/usr/include/c++/7/bits/stl_algobase.h:377:57: error: no type named ‘value_type’ in ‘struct std::iterator_traits<BigClass::Astruct>’
typedef typename iterator_traits<_II>::value_type _ValueTypeI;
^~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:378:57: error: no type named ‘value_type’ in ‘struct std::iterator_traits<BigClass::Astruct>’
typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
^~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:379:64: error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<BigClass::Astruct>’
typedef typename iterator_traits<_II>::iterator_category _Category;
^~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:383:9: error: no type named ‘value_type’ in ‘struct std::iterator_traits<BigClass::Astruct>’
const bool __simple = (__is_trivial(_ValueTypeI)
~~~~~~~~~~~~~~~~~~~~~~~~~~
&& __is_pointer<_II>::__value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&& __is_pointer<_OI>::__value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:386:44: error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<BigClass::Astruct>’
return std::__copy_move<_IsMove, __simple,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_Category>::__copy_m(__first, __last, __result);
~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
Some examples for vectors and int datatypes are available. Could anyone elaborate the appropriate sequence for std::copy for this kind of code structure?
Thanks.
std::copy is used instead of for loop, not with one.
std::copy(BCobj, BCobj + size, second_BCobj);
is essentially the same as
for(int i = 0; i < size; ++i) {
second_BCobj[i] = BCobj[i];
}
Also, don't forget to #include <algorithm> for std::copy
Explanation of arguments for std::copy:
std::copy takes as arguments 2 arguments of type matching InputIterator requirements and single argument of type OutputIteretor. Fortunately, pointers match these requirements, so we can use them directly. And because array name is interpreted as a pointer to its first element, we can pass it directly as argument to std::sort
Better version as suggested by Chef Gladiator:
std::copy(std::begin(BCobj), std::end(BCobj), std::begin(second_BCobj))
Welcome to Stack Overflow. You have presented your full code. Please next time also describe the development environment you are building in. Even better, try to present operating system agnostic and compiler agnostic, standard C++ code.
This is C++ forum, so we like to use standard C++ here. Your code is rewritten bellow using std::array. That makes it simple. Please study and enjoy the standard C++.
#include <array>
#include <iostream>
#include <algorithm>
namespace stack_overflow {
using namespace std;
struct BigClass final {
struct Astruct final {
double x[2], v[2];
int rank;
}one_struct;
friend ostream& operator << (ostream& os, Astruct const & one_struct)
{
return os << one_struct.rank << " " << one_struct.x[0] << " "
<< one_struct.x[1] << " " << one_struct.v[0] << " "
<< one_struct.v[1] ;
}
};
constexpr int size = 10;
using bcobj_arr = std::array<BigClass::Astruct, size>;
void populate( bcobj_arr& bcobjects_)
{
int j{ 0 };
for (auto& one_struct : bcobjects_) {
one_struct.x[0] = 1.1;
one_struct.x[1] = 1.2;
one_struct.v[0] = 2.1;
one_struct.v[1] = 2.2;
one_struct.rank = j++;
}
}
void print(const char prompt[BUFSIZ], bcobj_arr const & bcobjects_ )
{
cout << "\n\n" << prompt << "\n\n" ;
for (auto& one_struct : bcobjects_) {
cout << one_struct << "\n";
}
}
bool test (int argc, const char* argv[])
{
bcobj_arr BCobj;
populate(BCobj);
print("BCobj", BCobj);
// std::array instances can be copied
bcobj_arr second_BCobj = BCobj ;
print("second_BCobj", second_BCobj);
return true;
}
}
int main(const int argc, const char * argv[])
{
stack_overflow::test(argc, argv);
return 42;
}
Code is not commented at all. I assume you have a lot of questions, please do ask, in the comments bellow. I will try and answer them all by pointing you to the relevant documentation on-line.
Related
Say that you have a class that has an array member:
class A
{
private:
uint8_t length;
uint8_t arr[10];
public:
A(uint8_t length, const uint8_t array[]): length(length)
{
memcpy(arr, array, length);
}
};
Then you have a global constant object and you want to use uniform initialization like this:
const A A_CONST{1,{23}};
In this case the compiler gives an error: "invalid conversion from 'int' to 'const uint8_t*"
But this works:
const uint8_t arr[]={23};
const A A_CONST{1,arr};
But then you have an unnecessary global constant "arr" also. I don't understand why the compiler can't cast {23} to const uint8_t* by looking at the constructor. Why is this so and is there a workaround?
The constructor you defined, is equivalent to
A(uint8_t length, const uint8_t *array)
This is, what the compiler is trying to tell.
To have an initialization as in your example, you must use either another type, or a std::initializer_list, e.g.
#include <algorithm>
#include <initializer_list>
A(const std::initializer_list<uint8_t> array)
: length(array.size())
{
std::copy(array.begin(), array.end(), arr);
}
Apart from that, don't use plain arrays or (length, pointer) arguments. Better use modern types like std::array or std::vector, this is less error prone and you get this kind of initialization for free.
If you really need to use an array (instead of std::vector) you can use this example:
#include <cstring>
#include <cstdint>
#include <iostream>
#include <initializer_list>
class A
{
private:
static const uint8_t MAX_LENGTH = 10;
uint8_t length;
uint8_t arr[MAX_LENGTH];
public:
A(uint8_t _length, const uint8_t array[]): length(_length)
{
if (length > MAX_LENGTH) { // to prevent copying out of memory
length = MAX_LENGTH;
}
std::memcpy(arr, array, length);
}
A(std::initializer_list<uint8_t> l): length(l.size())
{
if (length > MAX_LENGTH) { // to prevent copying out of memory
length = MAX_LENGTH;
}
std::initializer_list<uint8_t>::iterator it = l.begin();
for (uint32_t i = 0; (i < length) || (it == l.end()); ++i, ++it) {
arr[i] = *it;
}
}
uint8_t printAllForExample() const {
for (uint32_t i = 0; i < length; ++i) {
std::cout << (int)arr[i] << " ";
}
std::cout << std::endl;
}
uint8_t getLengthForExample() const {
return length;
}
};
int main() {
std::cout << "A_CONST_1:" << std::endl;
const A A_CONST_1{23};
A_CONST_1.printAllForExample();
std::cout << "A_CONST_2:" << std::endl;
const A A_CONST_2{};
std::cout << (int)A_CONST_2.getLengthForExample() << std::endl;
A_CONST_2.printAllForExample();
std::cout << "A_CONST_3:" << std::endl;
const A A_CONST_3{0,1,2,3,4,5,6,7,8,9};
std::cout << (int)A_CONST_3.getLengthForExample() << std::endl;
A_CONST_3.printAllForExample();
std::cout << "A_CONST_4:" << std::endl;
const A A_CONST_4{0,1,2,3,4,5,6,7,8,9,10,11,12};
std::cout << (int)A_CONST_4.getLengthForExample() << std::endl;
A_CONST_4.printAllForExample();
uint8_t data[] = {30,40,50};
std::cout << "A_CONST_5:" << std::endl;
const A A_CONST_5(3, data);
std::cout << (int)A_CONST_5.getLengthForExample() << std::endl;
A_CONST_5.printAllForExample();
return 0;
}
How can I factor the following code, so that I can do loop through T = double and T = float? I have read about variadic templates but I
don't understand how to apply it in this case:
int main(int argc, char* argv[])
{
ofstream writeDat;
vector<int> nValues = {26,51,101,201};
for(int i = 0; i< 4; i++){
int N = nValues[i];
typedef float T ;
Matrix<T> a(N,N);
Matrix<T> b(N,3);
Matrix<T> x = Problem2<T>(N);
string sFloat = "2/" + to_string(N) + "Float"+".dat";
writeDat.open(sFloat);
for(int i =1; i<N ; i++)
writeDat << i << " " << x(i,1)<<endl;
writeDat << N <<" "<< x(N,1)<< endl;
writeDat.close();
}
for(int i = 0; i< 4; i++){
int N = nValues[i];
typedef double T ;
Matrix<T> a(N,N);
Matrix<T> b(N,3);
Matrix<T> x = Problem2<T>(N);
string s = "2/" + to_string(N) + "Double"+".dat";
writeDat.open(s);
for(int i =1; i<N ; i++)
writeDat << i << " " << x(i,1)<<endl;
writeDat << N <<" "<< x(N,1)<< endl;
writeDat.close();
}
return 0;
}
Use variadic expansion to call a template function (or variadic lambda) containing your duplicated logic:
#include<fstream>
#include<vector>
// the concept of a type wrapper
template<class T> struct type_wrapper;
// a model of type_wrapper for floats
template<>
struct type_wrapper<float> {
using type = float;
constexpr const char* name() const { return "Float"; }
};
// a model of type_wrapper for doubles
template<>
struct type_wrapper<double> {
using type = double;
constexpr const char* name() const { return "Double"; }
};
// call a template function once for each type wrapper in Ts...
template<class...Ts, class F>
auto for_each_type(F&& f)
{
(f(type_wrapper<Ts>()),...);
}
template<class T>
struct Matrix
{
Matrix(int, int);
T& operator()(int, int);
};
template<class T> Matrix<T> Problem2(int);
int main()
{
auto process = [](auto twrap) {
using T = typename decltype(twrap)::type;
std::ofstream writeDat;
std::vector<int> nValues = {26,51,101,201};
for(int i = 0; i< 4; i++){
int N = nValues[i];
Matrix<T> a(N,N);
Matrix<T> b(N,3);
Matrix<T> x = Problem2<T>(N);
std::string sFloat = "2/" + std::to_string(N) + twrap.name() + ".dat";
writeDat.open(sFloat);
for(int i =1; i<N ; i++)
writeDat << i << " " << x(i,1)<<std::endl;
writeDat << N <<" "<< x(N,1)<< std::endl;
writeDat.close();
}
};
for_each_type<double, float>(process);
}
https://godbolt.org/z/w6g6AC
Note:
You can make for_each_type more portable (i.e. work on c++14) like this:
template<class...Ts, class F>
auto for_each_type(F&& f)
{
#if __cplusplus >= 201703L
(f(type_wrapper<Ts>()),...);
#else
using expand = int[];
expand {
0,
(f(type_wrapper<Ts>()), 0)...
};
#endif
}
I have read about variadic templates but I don't understand how to
apply it in this case:
I believe what you are asking is answered most adequately by #RichardHodges. For reference sake, in case you want to be able to compare doing this the variadic template (since C++11) or fold expression (since C++17) way with doing this the function template only way (not that there's a special reason to do so), then you could use this snippet for example:
#include <vector>
#include <fstream>
using namespace std;
// Undefined struct
template <typename T> struct not_available;
// Non-specialized instantiations are not allowed, by using the undefined struct
template <typename T>
constexpr const char* type_string(){ return not_available<T>{}; }
// Specializing for `float`
template <>
constexpr const char* type_string<float>(){ return "Float"; }
// Specializing for `Double`
template <>
constexpr const char* type_string<double>(){ return "Double"; }
// Your classes
template<class T>
struct Matrix
{
Matrix(int, int);
T& operator()(int, int);
};
template<class T> Matrix<T> Problem2(int);
ofstream writeDat;
vector<int> nValues = {26,51,101,201};
// Your routine
template <typename T>
void func()
{
for(int i = 0; i< 4; i++){
int N = nValues[i];
Matrix<T> a(N,N);
Matrix<T> b(N,3);
Matrix<T> x = Problem2<T>(N);
string s = "2/" + to_string(N) + type_string<T>() +".dat";
writeDat.open(s);
for(int i =1; i<N ; i++)
writeDat << i << " " << x(i,1)<<endl;
writeDat << N <<" "<< x(N,1)<< endl;
writeDat.close();
}
}
int main(int argc, char* argv[])
{
func<float>();
func<double>();
return 0;
}
Note: This snippet tries to stick as much as possible to your original, but the absence of good enough reason I wouldn't necessarily advise using global variables, neither opting for using namespace std instead of referring to names with std::.
A few answers here (How to loop through a boost::mpl::list? being the one I started with) imply that I should be able to construct a generic lambda to feed to a boost::mpl::for_each() but I'm unable to find a working example, or build one myself.
Idealy what I would like to be able to do in a lambda is take a function like
template<typename T>
void TestFunction(const int &p)
{
T t(p);
std::cout << "p = " << p << ", t = " << t << std::endl;
};
that I'm currently calling in a loop with something like
for(int k = 0; k < 2; ++k)
{
TestFunction<int>(k);
TestFunction<long>(k);
TestFunction<float>(k);
TestFunction<double>(k);
};
and replace it with something like
typedef boost::mpl::list<int, long, float, double> ValidTypes;
for(int k = 0; k < 2; ++k)
{
// lambda definition that captures k
// boost::mpl::for_each(ValidTypes, ...) that calls the lambda.
};
Is this possible? If not with for_each() with one of the other mpl constructs? I've got a version of the code running where I overload operator() but I'd like to see a lambda solution if it's possible.
Thanks,
Andy.
If you can use C++14's generalized lambdas, you can capture the value of p and also infer the type of the current valid type being passed to the lambda:
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>
int main()
{
using ValidTypes = boost::mpl::list<int, long, float, double>;
for (auto k = 0; k < 2; ++k) {
boost::mpl::for_each<ValidTypes>([p = k](auto arg) {
using T = decltype(arg);
T t(p);
std::cout << "p = " << p << ", t = " << t << '\n';
});
}
}
Live Example.
Edit: for extra credit, here's a slightly more advanced version that also works for non-default constructible types:
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>
class NonDefaultConstructible
{
int value;
public:
NonDefaultConstructible(int const& p) : value(p) {}
friend auto& operator<<(std::ostream& ostr, NonDefaultConstructible const& ndc)
{
return ostr << ndc.value;
}
};
int main()
{
using ValidTypes = boost::mpl::list<int, long, float, double, NonDefaultConstructible>;
for (auto k = 0; k < 2; ++k) {
boost::mpl::for_each<ValidTypes, boost::mpl::make_identity<boost::mpl::_1>>([p = k](auto arg) {
using T = typename decltype(arg)::type;
T t(p);
std::cout << "p = " << p << ", t = " << t << '\n';
});
}
}
Live Example.
For an explanation of the somewhat convoluted use of make_identity, see my very first Q&A here!
I have a long list of some good old fashioned c style strings:
const char * p1key = PROPERTY_MAX_THREADS;
const char * p1value = "12";
const char * p2key = PROPERTY_MAX_FRAMES;
const char * p2value = "400";
const char * p3key = PROPERTY_MAX_FRAMEMEMORY;
const char * p3value = "140";
...
Then I do some stuff with them:
// write p1, p2, p3, pn to disk in fancy format
At the end I want to be able to write a loop and compare the written values to the original values.
int numProperties = 20;
for (int i = 0; i < numProperties; ++i) {
// on the first iteration, access p1 key/value
// on the second, access p2 key/value
// ...
}
How can I access p1 on the first iteration, p2 on the second, etc? Would an array of pointers help? I'm struggling to come up with the syntax to make this work. Any help would be very much appreciated.
Edit:
I would consider the best answer to show both the C and C++ way
INTRODUCTION
You'd have to store the pointers in some sort of container to be able to iterate over them in the manner as you propose.
Since you are dealing with pairs, std::pair from <utility> seems like a perfect match. Wrapping these std::pairs in a container such as std::vector will make it very easy to iterate over them in a clean manner.
SAMPLE IMPLEMENTATION
#include <iostream>
#include <utility>
#include <vector>
#define PROPERTY_MAX_THREADS "max_threads"
#define PROPERTY_MAX_FRAMES "max_frames"
#define PROPERTY_MAX_FRAMEMEMORY "max_fmemory"
const char * p1key = PROPERTY_MAX_THREADS;
const char * p1value = "12";
const char * p2key = PROPERTY_MAX_FRAMES;
const char * p2value = "400";
const char * p3key = PROPERTY_MAX_FRAMEMEMORY;
const char * p3value = "140";
int
main (int argc, char *argv[])
{
std::vector<std::pair<char const *, char const *>> properties {
{ p1key, p1value }, { p2key, p2value }, { p3key, p3value }
};
std::cout << "properties:\n";
for (auto& it : properties) {
std::cout << " " << it.first << " = " << it.second << "\n";
}
}
properties:
max_threads = 12
max_frames = 400
max_fmemory = 140
I TRIED THE ABOVE BUT IT DOESN'T COMPILE, WHY?
The previously written snippet makes use of features introduced in C++11, if you are unable to compile such code you will need to resort to functionality that your compiler does provide.
Below is a modified implementation that can be compiled by any compiler that supports C++03:
int const PROPERTIES_LEN = 3;
std::pair<char const *, char const*> properties[PROPERTIES_LEN] = {
std::make_pair (p1key, p1value),
std::make_pair (p2key, p2value),
std::make_pair (p3key, p3value)
};
for (int i = 0; i < PROPERTIES_LEN; ++i) {
std::cout << properties[i].first << " = " << properties[i].second << "\n";
}
You tagged it C++, so I'm going to give the C++ suggestion.
#include <iostream>
#include <vector>
#include <utility>
#define PROPERTY_MAX_THREADS "1"
#define PROPERTY_MAX_FRAMES "2"
#define PROPERTY_MAX_FRAMEMEMORY "3"
const char * p1key = PROPERTY_MAX_THREADS;
const char * p1value = "12";
const char * p2key = PROPERTY_MAX_FRAMES;
const char * p2value = "400";
const char * p3key = PROPERTY_MAX_FRAMEMEMORY;
const char * p3value = "140";
int main() {
using namespace std;
vector<pair<const char*,const char *>> collection =
{{p1key,p1value},{p2key,p2value},{p3key,p3value}};
for(auto &ele : collection){
cout << "key:" << ele.first
<< "value:" << ele.second << endl;
}
return 0;
}
alternatively just declare it as a collection from the beginning
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#define PROPERTY_MAX_THREADS "1"
#define PROPERTY_MAX_FRAMES "2"
#define PROPERTY_MAX_FRAMEMEMORY "3"
int main() {
using namespace std;
vector<pair<const string,const string>> collection =
{
{PROPERTY_MAX_THREADS, "12" },
{PROPERTY_MAX_FRAMES, "400"},
{PROPERTY_MAX_FRAMEMEMORY, "140"}
};
for(auto &ele : collection){
cout << "key:" << ele.first
<< " value:" << ele.second << endl;
}
return 0;
}
In C you can do this way.
#define STRA_END 0
const char* keyArray[] = {
"string1",
"string2",
"string3",
STRA_END
}
const char* valueArray[] = {
"string1",
"string2",
"string3",
STRA_END
}
main(){
int i;
for( i=0; keyArray[i]!=0; ++i )
doSometingToString(keyArray[i], valueArray[i]);
}
I organized two vectors of structures. Now I need to delete what is in chosen from points.
#include <StdAfx.h>;
#include <iostream>;
#include <vector>;
using namespace std;
struct SPoint
{
int id;
int X;
int Y;
};
vector<SPoint> points;
vector<SPoint> chosen;
void print_vect(const vector<SPoint> & vect)
{
for (int i = 0; i < vect.size(); ++i)
{
cout << vect[i].id << " (" << vect[i].X << "," << vect[i].Y << ")"<<endl;
}
cout << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
SPoint temp;
for (int i = 0; i < 10; i++)
{
temp.id = i;
temp.X = i;
temp.Y = i;
points.push_back(temp);
}
for (int i = 5; i < 10; i++)
{
temp.id = i;
temp.X = i;
temp.Y = i;
chosen.push_back(temp);
}
cout << "Points:" << endl;
print_vect(points);
cout << endl << endl;
cout << "Chosen:" << endl;
print_vect(chosen);
system("pause");
return 0;
}
There seems to be set_difference function. But the debugger tells me that I don't have a '<' method. It tells something like this:
error C2784: 'bool std::operator <(const std::move_iterator<_RanIt> &,const std::move_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::move_iterator<_RanIt> &' from 'SPoint
I study procedural programming in C++. And I don't know what to do with this method. And it seems to me that it is impossible to do anything here with "<".
Could you help me execute the subtraction?
Yes, you have guessed correctly. The std::set_difference function needs the < operator to function. It uses it to check equality as (!a
The comparison to check for equivalence of values, uses either
operator< for the first version, or comp for the second, in order to
test this; The value of an element, a, is equivalent to another one,
b, when (!a<b && !b<a) or (!comp(a,b) && !comp(b,a)).
All you would need to do is to add a function like below
bool operator<(const SPoint& p1, const SPoint&p2){
return p1.id <p2.id;
}
Assuming your id field is a unique field. Now you will be able to use the std::set_difference function. This compares two SPoint variables by their id fields.
Note that BOTH ranges need to be sorted for it to work correctly.
You could use e.g. std::remove_if:
std::remove_if(std::begin(points), std::end(points), [](const SPoint& point) {
// Try to find the point in the `chosen` collection
auto result = std::find_if(std::begin(chosen), std::end(chosen),
[](const SPoint& p) {
return (p.id == point.id)
});
// Return `true` if the point was found in `chosen`
return (result != std::end(chosen));
});
Note that I use C++11 lambda functions in the above code.