I have some template functions to aggregate a vector into a string in my C++ project. And I need to pass aggregation algorithm from one function to another using std::function.
template<typename T>
requires (is_convertible_v<T, BYTE> || is_convertible_v<T, CHAR> || is_convertible_v<T, WCHAR> || is_convertible_v<T, LPCSTR> || is_convertible_v<T, LPCWSTR>)
LPCWSTR StringHelper::ImplodeVectorToStringW(vector<T> vectorValues, LPCWSTR lpcwszSeparator)
{
wstring wstrSeparator(lpcwszSeparator);
function<wstring(wstring, T)> fn = [&](wstring total, T current) -> wstring { return total + lpcwszSeparator + ToWString(current); };
wstring wstrResult = Aggregate(vectorValues, wstring(L""), fn);
LPCWSTR lpcwszResult = GetStringBufferW(wstrResult);
return lpcwszResult;
}
template<typename TRet, typename TValue>
basic_string<TRet> Aggregate(vector<TValue> vectorValues, basic_string<TRet> initValue, function<basic_string<TRet>(basic_string<TRet>, TValue)> fnReduce)
{
basic_string<TRet> total = initValue;
for_each(vectorValues.begin(), vectorValues.end(), [&](TValue current) { fnReduce(total, current); });
return total;
}
template<typename T>
requires (is_convertible_v<T, BYTE> || is_convertible_v<T, CHAR> || is_convertible_v<T, WCHAR> || is_convertible_v<T, LPCSTR> || is_convertible_v<T, LPCWSTR>)
wstring StringHelper::ToWString(T Value)
{
wstring wstrResult;
if constexpr(is_convertible_v<T, BYTE>)
{
wstrResult = to_wstring((BYTE)Value);
}
else if constexpr(is_convertible_v<T, CHAR>)
{
wstrResult = AnsiToUnicode(string(1, (CHAR)Value).c_str());
}
else if constexpr(is_convertible_v<T, WCHAR>)
{
wstrResult = wstring(1, (WCHAR)Value);
}
else if constexpr(is_convertible_v<T, LPCSTR>)
{
wstrResult = AnsiToUnicode((LPCSTR)Value);
}
else if constexpr(is_convertible_v<T, LPCWSTR>)
{
wstrResult = (LPCWSTR)Value;
}
return wstrResult;
}
LPCWSTR StringHelper::AnsiToUnicode(LPCSTR lpcszValue)
{
LPWSTR lpwszResult = NULL;
if(!IsEmptyStringA(lpcszValue))
{
string strValue(lpcszValue);
int size = MultiByteToWideChar(CP_THREAD_ACP, 0, strValue.c_str(), -1, NULL, 0);
if(size > 0)
{
lpwszResult = new WCHAR[size];
if(!(MultiByteToWideChar(CP_THREAD_ACP, 0, strValue.c_str(), -1, lpwszResult, size) && lpwszResult != NULL))
{
delete[] lpwszResult;
lpwszResult = NULL;
}
}
}
return lpwszResult;
}
LPWSTR StringHelper::GetStringBufferW(LPCWSTR lpcwszValue)
{
LPWSTR lpwszBuffer = NULL;
if(lpcwszValue != NULL)
{
size_t size = wcslen(lpcwszValue) + 1;
lpwszBuffer = new WCHAR[size];
wcscpy_s(lpwszBuffer, size, lpcwszValue);
}
return lpwszBuffer;
}
LPWSTR StringHelper::GetStringBufferW(wstring wstrValue)
{
return GetStringBufferW(wstrValue.c_str());
}
But when I debug this code, function fn is initialized with the following value:
fn = wstrSeparator = L" ";
Not with required lambda expression. What is wrong?
4
What you do in the function template Aggregate
is call on each element of vectorValues
the callable fnReduce
, which in turn copies the input arguments total
and current
does something with them and then the returned value you discard. It is equivalent to NOOP. What exactly do you expect here to occur?
Learn basic C++. This is not Python, Java, or C#, where objects are stored dynamically by default.
First, you do a lot of string copying, which is not good, as you do a lot of unnecessary data copying.
Say, you could fix it by replacing:
function<wstring(wstring&, T const&)> fn = [&](wstring& total, T const& current)
{
total += lpcwszSeparator;
total += ToWString(current);
};
Then, you only need to adjust the Aggregate
argument parameters for it to work. Or alternatively, you could do as @Jarod42 suggested: replace the call inside for_each
with total = fnReduce(total, current);
which is slower but simpler.
1