Borbin the 🐱

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);