How can I create an std::array of char array? - c++11

I was trying to create a std::array of char array so that I could declare it static constexpr.
eg:
#include <array>
int main(){
static constexpr char A[] = "abc";
static constexpr char B[] = "def";
static constexpr std::array<char[], 3> tmp{A, B};
}
When I do this I get error message " too many initializers for"

By output of your compiler I could surmise that you have a non-standard extension active. Stricly ISO-wise use of char[] as parameter of template is not legal,. Some compilers would treat that as char[0].
what your array meant to store? way you're trying to do it would store adresses of array to char (and only way to do so would be replace char[] by by const char* in template parameters. std::array is trivial class which stores data statically so you cannot implement array with variable length of strings that way.
Either 1) abolish constexpr and use std::string 2) use const char* 3) worst case (which sometimes is the best) - use fixed array length or "naked" 2-dimensional array with aggregate initializer list.

You may use:
static constexpr std::array<char[4], 2> tmp {{{ A[0], A[1], A[2], A[3] },
{ B[0], B[1], B[2], B[3] }}};
or
static constexpr std::array<char[4], 2> tmp { "abc", "def" };
From http://en.cppreference.com/w/cpp/container/array:
When initializing an object of array type, the initializer must be either a string literal (optionally enclosed in braces) or be a brace-enclosed list of initialized for array members.
Thus you cannot initialize an array (member of std::array of char[4]) by an object of another array.

With C++20 std::to_array can be used.
static constexpr char A[] = "abc";
static constexpr char B[] = "def";
static constexpr auto tmp = std::to_array({A, B});

Related

Arrays declared globally gives out of scope error in functions

I have these arrays declared globally
char str1[] = "6541254939322816220209974565477289648317";
char str2[] = "3142522751761601737419090933147067701840";
int str1_size = strlen(str1);
int str2_size = strlen(str2);
int lcs[str1_size][str2_size];
int arrows[str1_size][str2_size];
But when I access this inside a function, it gives
lcs was not declared in this scope
also
array bound is not an integer constant before ‘]’ token
int lcs[str1_size][str2_size];
What am I doing wrong here ?
First of all
int a[dim];
where dim isn't a compile-time know constant (constexpr by example) isn't C++ standard; maybe it's possible with some extension with some compiler but isn't C++ standard.
So, in your case
int lcs[str1_size][str2_size];
int arrows[str1_size][str2_size];
where str1_size and str2_size are normal (not constexpr, not const initialized with literals) variables, is an error.
If you could redefine str1_size and str2_size as follows
constexpt int str1_size = strlen(str1);
constexpr int str2_size = strlen(str2);
the lcs and arrows definition could works.
Unfortunately (1) str1 and str2 aren't constexpr and (2) std::strlen() isn't constexpr.
But if declare str1/str2 constexpr and write a constexpr alternative to std::strlen...
#include <iostream>
constexpr std::size_t lenStr (char const * str)
{
std::size_t ret{};
while ( *(str++) )
++ret;
return ret;
}
constexpr char str1[] = "6541254939322816220209974565477289648317";
constexpr char str2[] = "3142522751761601737419090933147067701840";
constexpr auto str1_size = lenStr(str1);
constexpr auto str2_size = lenStr(str2);
int lcs[str1_size][str2_size];
int arrows[str1_size][str2_size];
int main ()
{
}
Unfortunately the preceding code require C++14 (in C++11 it's impossible write so complex constexpr functions).
In C++11 you should write lenStr() in a recursive way
constexpr std::size_t lenStr (char const * str, std::size_t ret = 0u)
{ return *str ? lenStr(++str, ++ret) : ret; }

Why there are two different answer in same compare template function

When I try to implement a template to compare two variables' value.
When I try passing string as parameters then the program couldn't compare the value right.
However when I add two same variables this code get me a right result.
Just as the picture shows.
You passed it a const char * pointer to compare and that will compare the pointer addresses, not the contents with '>'. As these are from different objects/strings, you have no way to know which will be first or last in memory, and it may vary from compile to compile, or even potentially run to run.
As you had the std::string local variable, I assume you intended to pass that, which does have comparison operators to compare the contents. If you want to pass a string literal as an std::string to such a template function, you must do it explicitly, such as:
Max<std::string>("a", "b"); // K is std::string, so both parameters will use the implicit constructor
Max(std::string("a"), std::string("b")); // Explicitly construct strings
If you do want Max to work with char pointers, you might overload or specialise it to use say strcmp, which does compare the contents.
template<class T> T Max(T x, T y)
{
return x > y ? x : y;
}
template<> const char* Max(const char *x, const char *y)
{
return strcmp(x, y) > 0 ? x : y;
}
template<> char* Max(char *x, char *y)
{
return strcmp(x, y) > 0 ? x : y;
}

Can I convert a non-const function argument to const and set the size of array?

Arrays require a constant to initialize the size. Hence, int iarr[10]
I thought I could possibly take a non-const argument and convert it to const then use it for an array size
int run(int const& size);
int run(int const& size)
{
const int csize = size;
constexpr int cesize = csize;
std::array<int, cesize> arr;
}
This, unfortunately doesn't work and I thought of using const_cast as
int run(int& size);
int run(int& size)
{
const int val = const_cast<int&>(size);
constexpr int cesize = val;
std::array<int, cesize> arr;
}
and this won't work either. I've read through a few SO posts to see if I can find anything
cannot-convert-argument-from-int-to-const-int
c-function-pass-non-const-argument-to-const-reference-parameter
what-does-a-const-cast-do-differently
Is there a way to ensure the argument is const when used as an initializer for the size of an array?
EDIT: I'm not asking why I can't initialize an array with a non-const. I'm asking how to initialize an array from a non-const function argument. Hence, initialize-array-size-from-another-array-value is not the question I am asking. I already know I can't do this but there may be a way and answer has been provided below.
std::array is a non-resizable container whose size is known at compile-time.
If you know your size values at compile-time, you can pass the value as a non-type template argument:
template <int Size>
int run()
{
std::array<int, Size> arr;
}
It can be used as follows:
run<5>();
Note that Size needs to be a constant expression.
If you do not know your sizes at compile-time, use std::vector instead of std::array:
int run(int size)
{
std::vector<int> arr;
arr.resize(size); // or `reserve`, depending on your needs
}
std::vector is a contiguous container that can be resized at run-time.
I'm asking how to initialize an array from a non-const function argument.
As you saw, it is not possible initialize an array size with an variable, because you need to specify the size or array at compiler time.
To solve your problem you should use std::vector that works like an array but you can resize it at run time. You can handle de vector as if you were handled an array, using the operator [], for example:
class MyClass
{
vector<char> myVector;
public:
MyClass();
void resizeMyArray(int newSize);
char getCharAt(int index);
};
MyClass::MyClass():
myVector(0) //initialize the vector to elements
{
}
void MyClass::resizeMyArray(int newSize)
{
myVector.clear();
myVector.resize(newSize, 0x00);
}
char MyClass::getCharAt(int index)
{
return myVector[index];
}
For more information check this link: http://www.cplusplus.com/reference/vector/vector/
Upgrade: Also, considere that std::array can't be resize, as this links say:
Arrays are fixed-size sequence containers: they hold a specific number of elements ordered in a strict linear sequence.

C++ template programming: why T[] and R(A1, A2, A3) are viewed as types?

For example:
std::unique_ptr<Box[]> Boxes(new Box[5]);
std::function<int(doube, double)> funcobj;
But for any variable x, decltype(x) cannot be T[] or call signature R(A1,...)
Thank you all for your helpful discussion.
Now I understand that both are truly types. You can use them in typedef declaration. But they are special you cannot use them as normal types. Here is an example to use these types.
typedef int function_type(int, int);
typedef char char_array[];
// char_array arr; // Not allowed
char_array str = "hello";
function_type add; // like function declaration;
// function add defined here.
int add(int a, int b) {
return a+b;
};

flatten vectors in a map

In C++, I have a map < int, vector < double > > or map < int, vector < some_Struct > >, I need to concatenate the vectors in this map and return the result.
The first version of the function is below:
#include <algorithm>
#include <vector>
vector < double >
flattenRecords(const map < int, vector < double > > & selected, int num_kept_reps)
{
vector < double > records;
int cnt = 0;
for (auto it = selected.begin(); it != selected.end(); ++it) {
records.insert(records.end(),
make_move_iterator(it->second.begin()),
make_move_iterator(it->second.end()));
cnt += 1;
if (cnt >= num_kept_reps)
break;
}
return records;
}
I know this is not what I intended to do, because I would like to keep the data in the map, and thus should not use make_move_iterator.
The codes can compile using g++ (GCC) 4.4.7 with the -std=c++0x flag.
So here is the question, I declare the map to be const, what happens when I try to use something like std::move to the vector in the map?
My second version is to use:
copy(it->second.begin(), it->second.end(), back_inserter(records));
I guess this does what I intend to do.
I am quite new to C++. The STL gives me a feeling of coding in python so I would like to try it.
Instead of using make_move_iterator(Iterator), just use Iterator if you would not like to move the elements. Eg:
records.insert(records.end(), it->second.begin(), it->second.end());
Your second version, as you guess, does indeed what you try to achieve.
Regarding your question about std::move on a const map, the std::move won't do anything in such a case. Since std::move is unconditional cast to rvalue, it'll cast the element to a const reference to an rvalue. Because it's const it'll match the lvalue ctor (copy ctor in this case), and not the move (copy) ctor.
Eg:
const std::string s1 = "Test";
const std::string s2 = std::move(s1);
This will invoke the copy constructor of std::string, not the move constructor. Hence, it'll do a copy, not a move.
This will do a move:
std::string s1 = "Test";
const std::string s2 = std::move(s1);
The s2 parameter in both examples does not have to be const. It makes no difference regarding the copy/move.
There is a 'pythonic' alternative, which you may like if you come from Python, using lambda and a "mapped-reduce" function
std::vector<double> merged = std::accumulate(selected.begin(),
selected.end(),
std::vector<double>(),
[](const std::vector<double>& a, std::vector<double>& b)
{
std::vector<double> result(a);
std::copy(b.begin(), b.end(), std::back_inserter(result));
return result;
});
);
std::move does not actually move data. It casts a reference to a r-value reference, which, if non-const, is a "movable" data type that move constructors can use. But it will never remove a const type qualifier, so using std::move on a const reference will not cast it to a movable type.

Resources