4

I need to copy the contents of a std::list into an array, wherein the array is struct of array. Below is the code implementation of it.

#include <iostream>
#include <string>
using namespace std;

typedef struct
{
    int height;
    int width;
    int length;
}dimensions;
GetDimensions(list<std::string>, *int); // Function that copies the content of list to array passed as second parameter

int main() 
{
    dimensions cuboid[10];
    int plane[10];

    list<std::string> planeList = GetList();//Function that returns list of elements
    list<std::string> dimensionList = GetList();

    GetDimensions(planeList,&plane);//This is fine, as it is a simple array
    GetDimensions(dimensionList,&cuboid.height);//Trouble in implementation of this usecase, for cuboid.height, cuboid.width and cuboid.height.
    return 0;
}

GetDimensions(list<std::string>dimensionList, int* dimensionParams)
{
    int i=0;
    for(list<std::string>::iterator it = dimensionList.begin(); it != dimensionList.end(); ++it)
    {
        dimensionParams[i] = stoi(*it);
        i++;
    }
}

Here, I need GetDimensions() function to copy the list (passed as first parameter) to array (second parameter). The implemented function works well for simple array plane. But how to pass the array of struct as parameter to the function ?

I will be getting the std::list as cuboid.height, cuboid.width and cuboid.length. So the function has to copy the contents of list from cuboid[0].height to cuboid[i].height respectively. Is there any specific function to copy the content directly?

JeJo
  • 30,635
  • 6
  • 49
  • 88
Nerdy
  • 1,016
  • 2
  • 11
  • 27
  • 4
    There is no need to `typedef struct { ... } abc;` in C++. Please just write `struct abc { ... };`. – Max Langhof Aug 20 '19 at 08:07
  • Regarding your question, there is no simple way in the language to say "all the `.height` subobjects in this array of `dimensions`". It's possible to build something that behaves like that, but it will be mostly ugly and incomprehensible. – Max Langhof Aug 20 '19 at 08:10
  • Also, did you mean `int* dimensionParams` in the `GetDimensions` signature? Right now it won't work for either `planeList` or `dimensionList` - you can't do `dimensionList[i]` if `dimensionList` is a plain `int`. – Max Langhof Aug 20 '19 at 08:11
  • Don't you get error message about declaring an `int` parameter for `GetDimensions()` and then accessing it by `dimensionParams[i]`? – the busybee Aug 20 '19 at 08:12
  • It is `int*`, also the list will always be less than size of array – Nerdy Aug 20 '19 at 08:17
  • 1
    That's clearly not C, so why that tag? Please read the description of tags before applying them, don't blindly suggest the suggested tags! – Ulrich Eckhardt Aug 20 '19 at 08:21
  • It's still not clear to me what you want to do or what's happening that's different from what you want. Are you trying to copy just the height fields? Are you trying to pretend `cuboid` is really just an array of 30 `int`s rather than 10 `dimensions`? Are you getting a compiler error or is there something different between when you copied and what you're trying to copy? – Adrian McCarthy Aug 20 '19 at 13:30

2 Answers2

4

Use std::array 's instead. Then your problem can be reduced to passing two different types of arrays to a single function.

This can be solved

  • either by good old function overloads
  • or in function template with if-constexpr.

Following is an example code with templated function with if-constexpr (See live online)

#include <iostream>
#include <string>
#include <list>
#include <array>
#include <type_traits>  // std::is_same_v

struct dimensions // no need to typedef here
{
        int height;
        int width;
        int length;
};

template<typename T>
void GetDimensions(const list<std::string>& dimensionList, T& dimensionParams) 
^^^^               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //---> pass list by const-ref as the values are non-modifying
{
    int i{0};
    if constexpr (std::is_same_v<std::array<int, 10>, T>)
    {
        for(const std::string& str: dimensionList)   dimensionParams[i++] = std::stoi(str);
    } 
    else
    {
        for(const std::string& str: dimensionList) dimensionParams[i++].height = std::stoi(str);
    }
}

int main()
 {
    std::array<dimensions, 10> cuboid;  // use std::array instead of VLA
    std::array<int, 10> plane;

    std::list<std::string> planeList{"1", "2"}; // some list
    std::list<std::string> dimensionList{"1", "2"};

    GetDimensions(planeList, plane);
    GetDimensions(dimensionList, cuboid);
    return 0;
}

Also note that:

  • You have not specified the return type of GetDimensions function. You probably want to return void there.
  • in C++ you do not need to use typedef alias for struct { ... }.

  • last but not least, do not practice with using namespace std;

JeJo
  • 30,635
  • 6
  • 49
  • 88
3

You can do this with boost::transform_iterator.

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <boost/iterator/transform_iterator.hpp>

struct dimensions {
    int height;
    int width;
    int length;
};

template <typename OutputIt>
void GetDimensions(std::list<std::string> dimensionList, OutputIt dimensionParams)
{
    // N.b. taking the address of a standard library function is undefined, so wrap in a lambda
    auto stoi = [](std::string s){ return std::stoi(s); };

    std::copy(boost::make_transform_iterator(dimensionList.begin(), stoi),
        boost::make_transform_iterator(dimensionList.end(), stoi), 
        dimensionParams);
}

int main() {
    dimensions cuboid[10];
    int plane[10];

    std::list<std::string> planeList = GetList();
    std::list<std::string> heightList = GetList();
    std::list<std::string> widthList = GetList();
    std::list<std::string> lengthList = GetList();

    GetDimensions(planeList, plane);
    GetDimensions(heightList, 
        boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::height)));
    GetDimensions(widthList, 
        boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::width)));
    GetDimensions(lengthList, 
        boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::length)));
    return 0;
}
Caleth
  • 52,200
  • 2
  • 44
  • 75