C++ aggregate using a lambda
13 October, 2024
For the EV diff plugin in cPicture, which calculates the exposure difference between pictures, I needed a simple aggregate to print the parameters used.
For example, the list values 1, 2 and 3 should be converted to the string "(1, 2, 3)". An aggregate function maps an enumerable type (vector) to a plain type (string). The function takes the vector, the toString lambda to convert individual vector elements to a string, and the start/end text and the separator.
I wanted to create a function similar to the Join-String function in PowerShell that is both simple and versatile. This is my implementation:
template<class T>
CString JoinString(typename vector<T>::const_iterator begin,
typename vector<T>::const_iterator end,
const function<CString(typename T)>& toString,
const CString& startText,
const CString& endText,
const CString& separator)
{
CString text(startText);
for (typename vector<T>::const_iterator it = begin; it != end; ++it)
{
// Use the lambda to convert the template type data to text.
text += toString(*it);
// Skip separator for last element.
if (it != end - 1)
{
text += separator;
}
}
return text + endText;
}
Test case for JoinString using int data.
The input is a vector of three ints which gets converted to a string that starts with an opening bracket '(', separates the elements with a comma ',' and ends with a closing bracket ')'. The toString lambda 'getText' converts the data to a string.
vector <unsigned int> matchList = { 1, 2, 3 };
// toString lambda expression
auto getText([](auto id) { CString text; text.Format(L"%d", id); return text; });
const CString matchParameter(JoinString<unsigned int>(matchList.begin(), matchList.end(), getText, L"(", L")", L", "));
Assert::AreEqual(L"(1, 2, 3)", matchParameter);
Test case for JoinString using string data.
The lambda simply passes the data and can be inlined.
vector <CString> strList = { L"a", L"b", L"c" };
const CString combinedText(JoinString<CString>(strList.begin(), strList.end(), [](auto text) { return text; }, L"[", L"]", L"+"));
Assert::AreEqual(L"[a+b+c]", combinedText);