1

I have a couple of string arrays in C++ that are defined as const strings

const string ABC[5] = {“1”,”2”,”3”,”4”,”5”};
const string DEF[3] = {“1”,”2”,”3”};

I need to pass each of them to the same function similar to this pseudo code:

void doSomething(string strArray[])
{
    // loop to access all strings in the array and do something .
};

But when called it gives me an error about type when it is passed to the function

doSomethign(ABC);
doSomethign(DEF);

This is the error generated

Error C2664 'void roster::strInput1(std::string [])': cannot convert argument 1 from 'const std::string [5]' to 'std::string []'

I have tried to use the const type as well but I am not sure what I am doing wrong.

6
  • Error C2664 'void roster::strInput1(std::string [])': cannot convert argument 1 from 'const std::string [5]' to 'std::string []' Commented May 4, 2019 at 6:54
  • Consider using a std::vector or a std::array. Commented May 4, 2019 at 7:01
  • 1
    void doSomething(const string strArray[]) works for me. Commented May 4, 2019 at 7:03
  • I would love to use vector as it makes sense to do that but it is a requirement for a class project that the data be input using const string[] Commented May 4, 2019 at 7:04
  • @vcp when I tired that the passed array is empty even though it is populated before. Commented May 4, 2019 at 7:19

3 Answers 3

5

ABC and DEF when passed as parameters decay to a pointer of type const string* which is not compatible with the type of strArray[].

Moreover, if you want to loop through the arrays inside the doSomething function, you will also need to pass the size of the arrays so as to know the bounds of the arrays. Since the sizes of ABC and DEF are different, what you need to use here is a function template.

Here is an example to loop through an array of T and print the elements.

template<typename T, size_t N>
void doSomething(T (&arr)[N])
{
    // loop to access all elements in the array and print them.
    for(auto const& var: arr)
        cout << var << '\n';
}

See Demo here.

If it is just a std::string array, you can just parameterize over the non-type parameter N which is the size of the array. The function template in this case will just be:

template<size_t N>
void doSomething(const std::string (&arr)[N])
{
    // loop to access all strings in the array and do something .
    for(auto const& str: arr)
        cout << str << '\n';
}
Sign up to request clarification or add additional context in comments.

4 Comments

I didn't think about this way its been a good 10 years since ive touched c++ but have started a class thanks for the help!
ABC ain't a pointer, it decays to a pointer. It's a const std::string[]
As the OP does not mention any other type than std::string in his question, I think it could be valuable to include also an example where you do no parameterize over the type T in the function template doSomething(...), but only over the non-type parameter N. Readers unfamiliar with (function) templates might think they must include the type parameterization for this (idiomatic) approach to work.
@dfri: Updated as per your comment. Thanks.
1

I disagree with the use of C-style arrays, I rather see std::array or std::vector. The 2 main issues with this are the loss of size-information and the decay to pointer behavior. That said, your underlying problem is const correctness.

For the purpose of simplicity, I'll rewrite your code to the equivalent based on std::vector next to the C-style variants. Please see the answer of P.W for why size information is important and how to deal with it. My answer is more focused on not introducing a templated method that requires you to expose the algorithm.

The following code defines a constant vector of strings. Once defined const, this should not change by the one receiving this object. (Ignoring mutable and const_cast).

const std::vector<std::string> ABC = {"1","2","3","4","5"};
const std::string ABC[] = {"1","2","3","4","5"};

As this object is created as const, it can never change and const_cast is undefined behavior. Mutable ain't used in std::string, so no internal state can change.

So what's happening with your function?

void doSomething(std::vector<std::string> &strArray);
void doSomething(std::string strArray[], size_t size);

This signature accepts a non-const vector of strings. Passing a const object to this function ain't allowed as this function signature allows modifications to the original instance.

So, how to fix: correct the signature to not allow any modifications. This is preferred if one doesn't modify its input arguments.

void doSomething(const std::vector<std::string> &strArray);
void doSomething(const std::string strArray[], size_t size);

Or if you need modifications, remove the const at creation:

 std::vector<std::string> ABC = {"1","2","3","4","5"};
 std::string ABC[] = {"1","2","3","4","5"};

As I've used std::vector instead of C-style arrays, we even get a third possibility that ain't possibles with the C-style arrays: pass by value.

void doSomething(std::vector<std::string> strArray)

In this case, the function gets a copy of the data. This could be useful if one has to do some manipulations to the vector without influencing the caller. For example: Convert all strings to upper case or sort the vector.

3 Comments

I think it's good that you expand also in this direction, but "So, how to fix: correct the signature to not allow any modifications: (preferred)" can be misleading. The idiomatic approach here would be to pass the array by reference, parameterizing over the size of the array as a non-type template parameter in a function template. With the approach above, the array to pointer decay will mean size information is lost in doSomething - how would we e.g. safely loop over the contents of the array argument (of different arrays sizes) when we only have a pointer in the body of doSomething?
... so +1 from me if you keep the const discussion, but consider mentioning the drawbacks/dangers of trying to write a size-agnostic function by simply stripping away the size information by means of array to pointer decay (and thus, loss of size).
@drfi: I didn't do that, assuming the C-arrays where a result of 'school education', I've rewrote the code with std::vector and the C-arrays (with size). The answer of P.W is more focussed on this size aspect and resolves the const-ness problem implicitly as the T-template-param takes this over.
-1

if you are passing const array try to write it in function too and put star instead of brackets.

void doSomething(const string *strArray)
{
// loop to access all strings in the array and do something .
};

1 Comment

your answer might solve the problem, though it doesn't explain why this is a right way of solving it. (Ps: I'm not responsible for the down vote)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.