Lets say I have a list of N arguments which I want to pass to a QString. The number N is variable and determined at runtime.
If I do this:
QString myString = "Some text %1, some other text %2,..., some more text %n"
for(auto arg : list) {
myString = myString.arg(arg);
}
I create a lot of string copies, as I can only change one .arg at a time, and need to save one copy of the string in each iteration. Is there a more efficient way? I looked into the documentation for something like QString::args(SomethingIteratable), but found nothing.
With some hard-coded limit (to transform runtime vector size to compile time one), you might use arg()
overload taking several QString
std::variant<
std::integral_constant<std:size_t, 1>,
std::integral_constant<std:size_t, 2>
std::integral_constant<std:size_t, 3>
std::integral_constant<std:size_t, 4>
std::integral_constant<std:size_t, 5>
// Adapt to your limit
>
as_integral_constant(std::size_t n) {
switch (n) {
case 1: return std::integral_constant<std:size_t, 1>{};
case 2: return std::integral_constant<std:size_t, 2>{};
case 3: return std::integral_constant<std:size_t, 3>{};
case 4: return std::integral_constant<std:size_t, 4>{};
case 5: return std::integral_constant<std:size_t, 5>{};
// adapt to your limit...
}
throw std::runtime_error("Unsupported size");
}
And then, visit
:
QString args(QString format, const std::vector<QString>& list)
{
const auto size = as_integral_constant(list.size());
return std::visit([&](auto N){
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return format.arg(list[Is]...);
}(std::make_index_sequence<N()>());
}, size);
}
Notice than arg
in one pass might behave differently than multipass, especially if your inserted texts contain %1
.