2

I've a function in a library (so, that I cannot change) like this:

char mName[MAX_PARAM_NAME_LEN];

void IParam::InitBool(const char* name) {
    strcpy(mName, name);
}

I'd like to pass text as Text0, Text1 (and so on) "faster", writing directly inside the function, starting from a text and an integer, without store additional variables on my own; such as:

int mIndex = 0;
InitBool("Text" + mIndex);

How would you do it? Wrap functions? Which one? Best approch? In C# thats pretty done, I find hard to do it in C++.

markzzz
  • 47,390
  • 120
  • 299
  • 507

2 Answers2

3

If your compiler supports C++17 features you could use a fold expression and string stream. The magic happens in the stringify() function which accepts zero or more arguments.

#include <iostream>
#include <sstream>
#include <string>

template <typename... Ts>
std::string stringify(const Ts&... args)
{
    std::ostringstream oss;
    (oss << ... << args);
    return oss.str();
}

void InitBool(const char *name)
{
    std::cout << name << '\n';
}

int main()
{
    int mIndex = 0;

    InitBool(stringify("Text", mIndex, '!', 1.0/3.0).c_str());
}

Live Demo

Blastfurnace
  • 18,411
  • 56
  • 55
  • 70
  • A bit modification to your code and [here is the C++11 solution](https://wandbox.org/permlink/bMbVSTiCgZba2yOf) so that OP can work with. ;) – JeJo Oct 04 '18 at 15:10
  • @JeJo That looks good, you might want to post that as an answer. – Blastfurnace Oct 04 '18 at 15:12
  • No... Since the idea is your, I would like to see in your answer. ;) You can update with. Also keep in mind that OP might need to clear the global ostringstream for the next time `InitBool()` call. – JeJo Oct 04 '18 at 15:19
1

In C++ "Text" is a const char[N], it's not actually a string type but just an array of characters with a null character ('\0') at the end. This doesn't support any sort of string manipulation. What you need to get is a std::string, which does support many string operations. Since you need to convert mIndex to a string to begin with we can just to that and the string that represents the number will handle concatenating "Text" to it. That gives you

int mIndex = 0;
InitBool(("Text" + std::to_string(mIndex)).c_str());

The ("Text" + std::to_string(mIndex)) part gives you a temporary std::string that is "Text0" and then the .c_str() gets a const char* to that string to pass to the function.


You can wrap the ("Text" + std::to_string(mIndex)) part in a function like

std::string concat(const char* str, int val)
{
    return str + std::to_string(val);
}

and then the function call would look like

InitBool(concat("Text", mIndex).c_str());
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • How would you wrap it to a function? So I can call it to `Concat("Text", mIndex)`? – markzzz Oct 04 '18 at 13:34
  • @markzzz you do not, you would get dangling pointer. You better use `std::string` instead of char array. – Slava Oct 04 '18 at 13:35
  • @markzzz I would just use `("Text" + std::to_string(mIndex)).c_str()` at the call site. Trying to wrap this in a function will be painful. You could make a macro, but I dislike that in this case. – NathanOliver Oct 04 '18 at 13:36
  • 1
    Or `InitBool(Concat("Text", mIndex).c_str())`. – Jarod42 Oct 04 '18 at 13:38
  • Possibly: `InitBool(param, "Text", m_Index)` with `template void InitBool(IParam&, Ts&&...)`. – Jarod42 Oct 04 '18 at 13:40
  • Tried somethings like this but its a pain: http://coliru.stacked-crooked.com/a/79d2f918e04948dc – markzzz Oct 04 '18 at 13:40
  • @markzz but you did not ask how to write a function that concatenates string and number but "no! I'm asking how to do it "on the fly", without using vars." – Öö Tiib Oct 04 '18 at 13:41
  • @markzzz I've updated the answer to wrap it in a function. – NathanOliver Oct 04 '18 at 13:46
  • @Jarod42 Good suggestion. I've added that to the answer. – NathanOliver Oct 04 '18 at 13:47
  • @markzzz: your method return dangling pointer. – Jarod42 Oct 04 '18 at 13:58
  • @NathanOliver so the memory allocated by the returned `std::string` will be cleaned up once exited from `InitBool` right? – markzzz Oct 04 '18 at 14:04
  • 1
    lifetime of that temporary ends at the end of full expression and so is valid inside `InitBool`. But in your sample, it ends at the end of full expression of `return`, so before `InitBool`. – Jarod42 Oct 04 '18 at 14:26
  • 1
    @markzzz Yes. The memory from the string returned by `concat` will be cleaned up after `InitBool` ends. – NathanOliver Oct 04 '18 at 14:52
  • @Jarod42: return? I mean the temporany var returned by that function, which is passed to InitBool. When will die it? – markzzz Oct 04 '18 at 14:52
  • Your way is invalid (`const char* concat(const char*, int)`) whereas proposed solution is valid: `std::string concat(const char*, int)`. You can still create dangling pointer with `const char* dangling = concat("t", 42).c_str();` but `InitBool(concat("t", 42).c_str())` is fine. – Jarod42 Oct 04 '18 at 14:57