2

I'm new here and this is my first question.

So, I have this function:

std::string join(string_initializer_list p_input) const {
    std::string output;
    for (auto const & s : p_input) {
        output.append(s);
    }
    return output;
}

The main objective of that function is to join a list of strings returning a new string.

For the parameter I've used a std::initializer_list<std::string> aliased as string_initializer_list.

The parameter is passed by value because after doing a bit of research, I noticed that I was just passing pointers around and that this was the most idiomatic and correct way to do so.

My question has to do with the for loop: which is more correct in this case and why? Should I use auto const & or auto &&?

The thing is: I don't want to change any of the strings from the initializer_list, and I want to leave that clear. From that perspective const & seems more correct but I would to know your opinions about this matter.

After doing some research, testing it in C++ and reading lots of questions here, I don't yet fully understand how auto && works.

Also, in a first draft I also had the parameter being passed as && as a way to prevent it from being an lvalue.

I intend only to use this function for quick stuff like this:

join({"Hello, ", "world"});

In rare ocasions, one of those std::strings will end up being an lvalue:

join({"Hello, ", some_string});

The main concept here is to make a cheap and easy way of concatenating strings. This is another function I made, similar with the one above but for a different context.

std::string & concatenate(std::string & p_output, string_initializer_list p_input) const {
    for (auto const & s : p_input) {
        p_output.append(s);
    }
    return p_output;
}

Once more, the perfectionist in me is asking about that for loop.

2
  • A couple of things you might want to consider in your function. One would be that you probably want to first compute the sum of the lengths, and then construct a string of that size before filling it in. As for the loop. It won't matter much whether you use const auto& or auto&& in the grand scheme of things as the underlying object types are of type const string so type deduction for the universal reference should yield const string& same as const auto& would. (A more efficient function might actually be one using variadic templates to do the work instead of a loop.) Commented Nov 23, 2016 at 5:28
  • Thanks! Should I use another loop to calculate the final length and then call reserve on the final string? Wouldn't another loop be a bit too much? I mean, I understand your point. I knew about the variadic template thing, the problem with the template solution is that, well, they should be generic and in my case I just want something that works on strings, also many implementations of variadic templates for string concatenation uses ostringstream just to ensure that most of the stuff gets turned into a string. Commented Nov 23, 2016 at 12:13

1 Answer 1

1

The iterator type of std::initializer_list<T> is const T*. So when you dereference it, you get an lvalue of type const T. It does not matter whether you use const auto& or auto&& to iterate since either way you will get an lvalue reference to const T. I would prefer const auto& here for readability---auto&& often suggests you're working with template code in which the thing could be either an lvalue or an rvalue.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the response ;)

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.