I'm trying to figure this out, and, it's really annoying me. I have a function that converts either an array or a vector into a vector of complex numbers, but, I do not know how it would be possible for the function to be able to accept both double arrays, as well as double vectors. I've tried using templates, but, this does not seem to work.template
template<typename T>
vector<Complex::complex> convertToComplex(T &vals)
{
}
Value::Value(vector<double> &vals, int N) {
};
Value::Value(double *vals, int N) {
};
What I am hoping for is this:
int main()
{
double[] vals = {1, 2, 3, 4, 5};
int foo = 4;
Value v(vals, foo); // this would work and pass the array to the constructor, which would
// then pass the values to the function and covert this to a
// vector<complex>
}
I could do the same for a vector as well.. I don't know whether or not templates are the right approach for this.
You could make your function and constructor a template that takes two iterators:
template<typename Iterator>
vector<Complex::complex> convertToComplex(Iterator begin, Iterator end)
{
}
class Value
{
public:
template <Iteraror>
Value(Iterator begin, Iterator end)
{
vector<Complex::complex> vec = comvertToComplex(begin, end);
}
....
};
then
double[] vals = {1, 2, 3, 4, 5};
Value v(std::begin(vals), std::end(vals));
std::vector<double> vec{1,2,3,4,5,6,7};
Value v2(v.begin(), v.end());
I have omitted foo because it isn't very clear to me what its role is.
No need to define a template function here if you only want to support doubles.
You should do it like this, it's much simpler:
vector<Complex::complex> convertToComplex(const double* array, size_t len)
{
// ... your implementation
}
vector<Complex::complex> convertToComplex(const vector<double>& v, size_t len)
{
return convertToComplex(v.data(), len);
}
That's it!
Related
In C++11, how would I go about writing a function (or method) that takes a std::array of known type but unknown size?
// made up example
void mulArray(std::array<int, ?>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6> arr2;
std::array<int, 95> arr3;
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
During my search I only found suggestions to use templates, but those seems messy (method definitions in header) and excessive for what I'm trying to accomplish.
Is there a simple way to make this work, as one would with plain C-style arrays?
Is there a simple way to make this work, as one would with plain C-style arrays?
No. You really cannot do that unless you make your function a function template (or use another sort of container, like an std::vector, as suggested in the comments to the question):
template<std::size_t SIZE>
void mulArray(std::array<int, SIZE>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
Here is a live example.
The size of the array is part of the type, so you can't do quite what you want. There are a couple alternatives.
Preferred would be to take a pair of iterators:
template <typename Iter>
void mulArray(Iter first, Iter last, const int multiplier) {
for(; first != last; ++first) {
*first *= multiplier;
}
}
Alternately, use vector instead of array, which allows you to store the size at runtime rather than as part of its type:
void mulArray(std::vector<int>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
EDIT
C++20 tentatively includes std::span
https://en.cppreference.com/w/cpp/container/span
Original Answer
What you want is something like gsl::span, which is available in the Guideline Support Library described in the C++ Core Guidelines:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-views
You can find an open-source header-only implementation of the GSL here:
https://github.com/Microsoft/GSL
With gsl::span, you can do this:
// made up example
void mulArray(gsl::span<int>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6> arr2;
std::array<int, 95> arr3;
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
The problem with std::array is that its size is part of its type, so you'd have to use a template in order to implement a function that takes an std::array of arbitrary size.
gsl::span on the other hand stores its size as run-time information. This allows you to use one non-template function to accept an array of arbitrary size. It will also accept other contiguous containers:
std::vector<int> vec = {1, 2, 3, 4};
int carr[] = {5, 6, 7, 8};
mulArray(vec, 6);
mulArray(carr, 7);
Pretty cool, huh?
Absolutely, there is a simple way in C++11 to write a function that takes a std::array of known type, but unknown size.
If we are unable to pass the array size to the function, then instead, we can pass the memory address of where the array starts along with a 2nd address of where the array ends. Later, inside of the function, we can use these 2 memory addresses to calculate the size of the array!
#include <iostream>
#include <array>
// The function that can take a std::array of any size!
void mulArray(int* piStart, int* piLast, int multiplier){
// Calculate the size of the array (how many values it holds)
unsigned int uiArraySize = piLast - piStart;
// print each value held in the array
for (unsigned int uiCount = 0; uiCount < uiArraySize; uiCount++)
std::cout << *(piStart + uiCount) * multiplier << std::endl;
}
int main(){
// initialize an array that can can hold 5 values
std::array<int, 5> iValues{ 5, 10, 1, 2, 4 };
// Provide a pointer to both the beginning and end addresses of
// the array.
mulArray(iValues.begin(), iValues.end(), 2);
return 0;
}
Output at Console:
10, 20, 2, 4, 8
I tried below and it just worked for me.
#include <iostream>
#include <array>
using namespace std;
// made up example
void mulArray(auto &arr, const int multiplier)
{
for(auto& e : arr)
{
e *= multiplier;
}
}
void dispArray(auto &arr)
{
for(auto& e : arr)
{
std::cout << e << " ";
}
std::cout << endl;
}
int main()
{
// lets imagine these being full of numbers
std::array<int, 7> arr1 = {1, 2, 3, 4, 5, 6, 7};
std::array<int, 6> arr2 = {2, 4, 6, 8, 10, 12};
std::array<int, 9> arr3 = {1, 1, 1, 1, 1, 1, 1, 1, 1};
dispArray(arr1);
dispArray(arr2);
dispArray(arr3);
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
dispArray(arr1);
dispArray(arr2);
dispArray(arr3);
return 0;
}
Output:
1 2 3 4 5 6 7
2 4 6 8 10 12
1 1 1 1 1 1 1 1 1
3 6 9 12 15 18 21
10 20 30 40 50 60
2 2 2 2 2 2 2 2 2
This can be done, but it takes a few steps to do cleanly. First, write a template class that represents a range of contiguous values. Then forward a template version that knows how big the array is to the Impl version that takes this contiguous range.
Finally, implement the contig_range version. Note that for( int& x: range ) works for contig_range, because I implemented begin() and end() and pointers are iterators.
template<typename T>
struct contig_range {
T* _begin, _end;
contig_range( T* b, T* e ):_begin(b), _end(e) {}
T const* begin() const { return _begin; }
T const* end() const { return _end; }
T* begin() { return _begin; }
T* end() { return _end; }
contig_range( contig_range const& ) = default;
contig_range( contig_range && ) = default;
contig_range():_begin(nullptr), _end(nullptr) {}
// maybe block `operator=`? contig_range follows reference semantics
// and there really isn't a run time safe `operator=` for reference semantics on
// a range when the RHS is of unknown width...
// I guess I could make it follow pointer semantics and rebase? Dunno
// this being tricky, I am tempted to =delete operator=
template<typename T, std::size_t N>
contig_range( std::array<T, N>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, std::size_t N>
contig_range( T(&arr)[N] ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, typename A>
contig_range( std::vector<T, A>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
};
void mulArrayImpl( contig_range<int> arr, const int multiplier );
template<std::size_t N>
void mulArray( std::array<int, N>& arr, const int multiplier ) {
mulArrayImpl( contig_range<int>(arr), multiplier );
}
(not tested, but design should work).
Then, in your .cpp file:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
This has the downside that the code that loops over the contents of the array doesn't know (at compile time) how big the array is, which could cost optimization. It has the advantage that the implementation doesn't have to be in the header.
Be careful about explicitly constructing a contig_range, as if you pass it a set it will assume that the set data is contiguous, which is false, and do undefined behavior all over the place. The only two std containers that this is guaranteed to work on are vector and array (and C-style arrays, as it happens!). deque despite being random access isn't contiguous (dangerously, it is contiguous in small chunks!), list is not even close, and the associative (ordered and unordered) containers are equally non-contiguous.
So the three constructors I implemented where std::array, std::vector and C-style arrays, which basically covers the bases.
Implementing [] is easy as well, and between for() and [] that is most of what you want an array for, isn't it?
I have seen here :http://www.cplusplus.com/doc/tutorial/arrays/
that
int[N] is the same as std::array<int,N> in C++.
I would like to use this notation in order to avoid to pass N as an argument of a function.
I would like to do something like that
returnedType function(array tab)
instead of
returnedType function(int tab, int N)
but i can't make the type array because i must write array<int,N> and i don't know N in advance.
Has Somebody a solution?
Make the function a function template, like so:
template <size_t N>
void function(std::array<int, N> arr)
{
// do something with arr
}
and call it like:
int main()
{
std::array<int, 3> a;
function(a);
std::array<int, 15> b;
function(b);
}
if you do not know the size in advance, std::vector is what you want
//function taking vector:
int MyFunc(const std::vector<int>& vec)
{
//.. do stuff
return 5;
}
std::vector<int> myvec;
//add somme entries:
myvec.push_back(1);
myvec.push_back(2);
myvec.push_back(3);
//call function:
int res = MyFunc(myvec);
I would like to modernize a small mathematical library using new C++ paradigms (I have a C++17 compiler). In specific, I need to pass an array to a class through constructor.
This is the "classical" old way I used. It works
class Vector {
public:
long double* elements;
public:
Vector(int size, long double *array) {
elements = new long double[size];
for(int i = 0; i < size; i++) {
elements[i] = array[i];
}
};
virtual ~Vector() {
delete []elements;
}
};
int main() {
long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Vector vector = Vector(10, array);
for (int i = 0; i < 10; i++) {
std::cout << vector.elements[i] << std::endl;
}
return 0;
}
So, I tried to change Vector class with what I have understood about variadic templates and parameter pack. It doesn't work
class Vector {
public:
long double* elements;
public:
template<typename... Args>
Vector(Args... args){
constexpr int size = sizeof...(Args);
elements = new long double[size]{args...};
}
};
int main() {
long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Vector vector = Vector(array);
for (int i = 0; i < 10; i++) {
std::cout << vector.elements[i] << std::endl;
}
return 0;
}
The error returned by compiler is
error: cannot convert ‘long double*’ to ‘long double’ in initialization
elements = new long double[size]{args...};
What am I doing wrong?
Further, I'm wondering if it is possible to use a std::array instead of raw array, both either inside main method and in Vector class.
To pass an array like that variadic templates are not the solution. Variadic templates are used to pass N numbers of parameters to a class/function. Yet you are passing only one parameter!
I would suggest you to
I suggest you tu use array references, which are available in all C++ versions:
class Vector {
public:
long double* elements;
public:
template<std::size_t size>
Vector(long double (&array)[size]) {
elements = new long double[size];
for(int i = 0; i < size; i++) {
elements[i] = array[i];
}
};
virtual ~Vector() {
delete []elements;
}
};
By the way, if you can, use vector. I highly doubt this custom vector class is as efficient as std::vector (no geometric growth or optimized copy and move)
I'm not sure if this answers your question, but I would give you a general advice:
I guess you want to encapsulate your own logic into the vector.
The standard library vector is very advanced and you should use it, instead of loosing time to write your own low-level code. You could concentrate more on the logic you need.
Your could define your own vector and still use the advantages of the std::vector for constructing your Vector objects.
For example with inheritance:
template<typename T>
class Vector : public std::vector<int>
{
// here comes the implementation of your interface.
}
or composition:
template<typename T>
class Vector {
private:
std::vector<T> elems;
}
In the case of composition you'd have to define the constructors you need.
In both cases you could then use your own Vector as follows:
Vector<double> vec1(10); // construct vector with 10 double's each = 0
Vector<double> vec2(10, 5); // construct vector with 10 double's each = 5
Vector<double> vec3{1,2,3,4}; // using initializer list
Vector<double> vec4(somecontainer.begin(), somecontainer.end()); // construct vector by copying elemts from some other container
etc.
As you see with std::vector you'are getting all the benefits you need for constructing your own Vector object.
According to your definition of
template<typename... Args> Vector(Args... args);
You want to use this constructor in this way:
Vector vector = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
It is possible, if you sightly modify your definition of the constructor to:
template<typename... Args>
Vector(Args... args){
constexpr int size = sizeof...(Args);
elements = new long double[size]{static_cast<long double>(args)...};
}
Please note such kind of use is not good practice, you should normally use std containers and avoid new operator.
In C++11, how would I go about writing a function (or method) that takes a std::array of known type but unknown size?
// made up example
void mulArray(std::array<int, ?>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6> arr2;
std::array<int, 95> arr3;
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
During my search I only found suggestions to use templates, but those seems messy (method definitions in header) and excessive for what I'm trying to accomplish.
Is there a simple way to make this work, as one would with plain C-style arrays?
Is there a simple way to make this work, as one would with plain C-style arrays?
No. You really cannot do that unless you make your function a function template (or use another sort of container, like an std::vector, as suggested in the comments to the question):
template<std::size_t SIZE>
void mulArray(std::array<int, SIZE>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
Here is a live example.
The size of the array is part of the type, so you can't do quite what you want. There are a couple alternatives.
Preferred would be to take a pair of iterators:
template <typename Iter>
void mulArray(Iter first, Iter last, const int multiplier) {
for(; first != last; ++first) {
*first *= multiplier;
}
}
Alternately, use vector instead of array, which allows you to store the size at runtime rather than as part of its type:
void mulArray(std::vector<int>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
EDIT
C++20 tentatively includes std::span
https://en.cppreference.com/w/cpp/container/span
Original Answer
What you want is something like gsl::span, which is available in the Guideline Support Library described in the C++ Core Guidelines:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-views
You can find an open-source header-only implementation of the GSL here:
https://github.com/Microsoft/GSL
With gsl::span, you can do this:
// made up example
void mulArray(gsl::span<int>& arr, const int multiplier) {
for(auto& e : arr) {
e *= multiplier;
}
}
// lets imagine these being full of numbers
std::array<int, 17> arr1;
std::array<int, 6> arr2;
std::array<int, 95> arr3;
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
The problem with std::array is that its size is part of its type, so you'd have to use a template in order to implement a function that takes an std::array of arbitrary size.
gsl::span on the other hand stores its size as run-time information. This allows you to use one non-template function to accept an array of arbitrary size. It will also accept other contiguous containers:
std::vector<int> vec = {1, 2, 3, 4};
int carr[] = {5, 6, 7, 8};
mulArray(vec, 6);
mulArray(carr, 7);
Pretty cool, huh?
Absolutely, there is a simple way in C++11 to write a function that takes a std::array of known type, but unknown size.
If we are unable to pass the array size to the function, then instead, we can pass the memory address of where the array starts along with a 2nd address of where the array ends. Later, inside of the function, we can use these 2 memory addresses to calculate the size of the array!
#include <iostream>
#include <array>
// The function that can take a std::array of any size!
void mulArray(int* piStart, int* piLast, int multiplier){
// Calculate the size of the array (how many values it holds)
unsigned int uiArraySize = piLast - piStart;
// print each value held in the array
for (unsigned int uiCount = 0; uiCount < uiArraySize; uiCount++)
std::cout << *(piStart + uiCount) * multiplier << std::endl;
}
int main(){
// initialize an array that can can hold 5 values
std::array<int, 5> iValues{ 5, 10, 1, 2, 4 };
// Provide a pointer to both the beginning and end addresses of
// the array.
mulArray(iValues.begin(), iValues.end(), 2);
return 0;
}
Output at Console:
10, 20, 2, 4, 8
I tried below and it just worked for me.
#include <iostream>
#include <array>
using namespace std;
// made up example
void mulArray(auto &arr, const int multiplier)
{
for(auto& e : arr)
{
e *= multiplier;
}
}
void dispArray(auto &arr)
{
for(auto& e : arr)
{
std::cout << e << " ";
}
std::cout << endl;
}
int main()
{
// lets imagine these being full of numbers
std::array<int, 7> arr1 = {1, 2, 3, 4, 5, 6, 7};
std::array<int, 6> arr2 = {2, 4, 6, 8, 10, 12};
std::array<int, 9> arr3 = {1, 1, 1, 1, 1, 1, 1, 1, 1};
dispArray(arr1);
dispArray(arr2);
dispArray(arr3);
mulArray(arr1, 3);
mulArray(arr2, 5);
mulArray(arr3, 2);
dispArray(arr1);
dispArray(arr2);
dispArray(arr3);
return 0;
}
Output:
1 2 3 4 5 6 7
2 4 6 8 10 12
1 1 1 1 1 1 1 1 1
3 6 9 12 15 18 21
10 20 30 40 50 60
2 2 2 2 2 2 2 2 2
This can be done, but it takes a few steps to do cleanly. First, write a template class that represents a range of contiguous values. Then forward a template version that knows how big the array is to the Impl version that takes this contiguous range.
Finally, implement the contig_range version. Note that for( int& x: range ) works for contig_range, because I implemented begin() and end() and pointers are iterators.
template<typename T>
struct contig_range {
T* _begin, _end;
contig_range( T* b, T* e ):_begin(b), _end(e) {}
T const* begin() const { return _begin; }
T const* end() const { return _end; }
T* begin() { return _begin; }
T* end() { return _end; }
contig_range( contig_range const& ) = default;
contig_range( contig_range && ) = default;
contig_range():_begin(nullptr), _end(nullptr) {}
// maybe block `operator=`? contig_range follows reference semantics
// and there really isn't a run time safe `operator=` for reference semantics on
// a range when the RHS is of unknown width...
// I guess I could make it follow pointer semantics and rebase? Dunno
// this being tricky, I am tempted to =delete operator=
template<typename T, std::size_t N>
contig_range( std::array<T, N>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, std::size_t N>
contig_range( T(&arr)[N] ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
template<typename T, typename A>
contig_range( std::vector<T, A>& arr ): _begin(&*std::begin(arr)), _end(&*std::end(arr)) {}
};
void mulArrayImpl( contig_range<int> arr, const int multiplier );
template<std::size_t N>
void mulArray( std::array<int, N>& arr, const int multiplier ) {
mulArrayImpl( contig_range<int>(arr), multiplier );
}
(not tested, but design should work).
Then, in your .cpp file:
void mulArrayImpl(contig_range<int> rng, const int multiplier) {
for(auto& e : rng) {
e *= multiplier;
}
}
This has the downside that the code that loops over the contents of the array doesn't know (at compile time) how big the array is, which could cost optimization. It has the advantage that the implementation doesn't have to be in the header.
Be careful about explicitly constructing a contig_range, as if you pass it a set it will assume that the set data is contiguous, which is false, and do undefined behavior all over the place. The only two std containers that this is guaranteed to work on are vector and array (and C-style arrays, as it happens!). deque despite being random access isn't contiguous (dangerously, it is contiguous in small chunks!), list is not even close, and the associative (ordered and unordered) containers are equally non-contiguous.
So the three constructors I implemented where std::array, std::vector and C-style arrays, which basically covers the bases.
Implementing [] is easy as well, and between for() and [] that is most of what you want an array for, isn't it?
How do I define a typedef for a fixed length array so that I can also 'new'. The following does not work:
typedef double Vector[3];
Vector *v = new Vector; // does not compile
We are trying to wrap into C++ some old C code which handles float * and float (*)[3] in a generic way.
The pointer to an double[3] is double * - so this will work:
typedef double Vector[3];
double *v = new Vector;
But I suggest you don't use it that way - to delete the array you need the array-delete-operator:
delete[] v;
But on new Vector you don't see it is an array and so it might be forgotten.
This case is handled (and strongly recommended to avoid) in Scott Meyers Effective C++. So better don't use an typedef here.
class Vector
{
public: // methods
double * data() { return mData; }
const double * data() const { return mData; }
double & operator[](int i) { return mData[i]; }
double operator[](int i) const { return mData[i]; }
private: // attributes
double mData[3];
};
will allow
Vector * pv = new Vector;
Vector & v = *pv;
v[0] = 1;
v[1] = 2;
v[2] = 3;
pass_it_to_legacy_lib(v.data());
delete pv;
One issue with your original example is that it would invoke the new operator where the new[] would actually be correct. Also, it would make it non-obvious that delete[] had to be used instead of plain delete.
The class approach doesn't need new[] and takes full advantage of the apriori fixed length.
If you're happy to use templates in your C++ code, something like this could work..
template <typename T, int S>
struct array
{
array() : _inst() {}
template<typename _F>
void operator()(_F & f)
{
f(_inst);
}
operator T*() { return _inst; }
// real array
T _inst[S];
};
typedef array<double, 4> d4;
void foo(double*)
{
}
int main(void)
{
d4 d; // no need for new, but you can use if you want
// first way to call is to pass the function to the array object, which will then
// visit
d(foo);
// take advantage of the type operator (operator T*)
foo(d);
}
#include <cassert>
#include <vector>
using namespace std;
template<typename Type, int Dimension>
const vector<Type> make_fixed_vector(const Type& value = Type())
{
return vector<Type>(Dimension, value);
}
int main(void)
{
vector<int> v3 = make_fixed_vector<int, 3>();
assert(v3.size() == 3);
}
C++1x compilers are able to deduce the type of a variable, which is handy when declaring multi-dimensional "fixed" vectors using this technique:
.
.
.
template<typename Type, int Rows, int Columns>
const vector<vector<Type> > make_fixed_vector_vector(const Type& value = Type())
{
return vector<vector<Type> >(Rows, make_fixed_vector<Type, Columns>(value));
}
int main(void)
{
auto vv = make_fixed_vector_vector<int, 3, 4>(42);
assert(vv.size() == 3);
assert(vv[0].size() == 4);
assert(vv[0][0] == 42);
assert(vv[2][3] == 42);
}
I had this simple idea when programming a parser-function for list expressions which shall return a fixed-size vector of vector of integers. For example, a vector<vector<int> >(1) for a expression like "(0,8)", but a vector<vector<int> >(2) for a expression like "(3-4)(5)" and so on. In the application up to 5 parenthesized definitions are possible, which represent logical references to program data. I first try to parse a vector<vector<int> >(5). Worked? Ok, got reference type A, the most detailed one. Otherwise vector<vector<int> >(4) indicates a reference type B etc.
For this purpose make_fixed_vector worked well, but from a general perspective the technique has flaws. Most notably, since make_fixed_vector returns no true type, its dimension(s) cannot be checked at compile-time. At runtime reserve, resize and push_back calls are possible. And, since function templates cannot have default template arguments, custom allocators require more typing:
template<typename Type, int Dimension, template<typename> class Allocator>
const vector<Type Allocator<Type> > make_fixed_vector(const Type& value = Type())
{
return vector<Type, Allocator<Type> >(Dimension, value);
}
vector<int> v3 = make_fixed_vector<int, 3, std::allocator>();
etc. etc. But this technique keeps smaller projects basic. Unless this virtue is relevant Boost's boost::array might be more realistic.