所以我写了这个模板化的可变参数函数ConcatBstr()
来连接多个BSTR字符串。
但是,其他用户正在使用BSTR以外的其他类型的参数来调用它。尽管也可以使该函数接受WCHAR,但是其他字符串类型确实与之不兼容。
第一季度:如何将ConcatBstr()
接受的参数类型适当地限制为仅BSTR?
UINT LenSum() { // Stop condition
return 0;
}
template <typename T, typename... Args> // General case
UINT LenSum(T bstr, Args... args) {
return SysStringLen(bstr) + LenSum(args...);
}
void AppendBstr(WCHAR* dest) { // Stop condition
*dest = L'\0'; //Add the terminating zero. SysReAllocStringLen() allocated 1 more wchar_t for it already
}
template <typename T, typename... Args> // General case
void AppendBstr(WCHAR* dest, T src, Args... args) {
UINT n = SysStringLen(src);
wmemcpy(dest, BSTR(src), n);
AppendBstr(dest + n, args...);
}
BSTR ConcatBstr(BSTR* s) { return *s; }
template <typename... ADDTHIS>
BSTR ConcatBstr(BSTR* dest, ADDTHIS... addthis) {
UINT n = SysStringLen(*dest);
SysReAllocStringLen( dest, *dest, n + LenSum(addthis...) ); //Call this expensive function only ONCE !
AppendBstr( *dest + n, addthis...);
return *dest;
}
int main(int argc, char* argv[]) { //Usage
BSTR s1 = SysAllocString(L"Quick");
BSTR s2 = SysAllocString(L"Fox");
BSTR s3 = SysAllocString(L"Jumped");
BSTR s4 = SysAllocString(L"Over");
wcout << ConcatBstr(&s1, s2, s3, s4) << endl;
//I know that these BSTRs need to be freed eventually
}
第二季度:能否在保留仅调用一次SysReAllocStringLen()
的属性的同时改进此代码?
答案 0 :(得分:1)
A1 :不确定您的要求是什么,因为编译器已经拒绝任何传递不兼容类型的尝试,因为模板实例化有时会失败。但是您可以使用std::enable_if
或static_assert
来获得更具描述性的错误消息。
A2:使用C ++ 17,您可以使用fold表达式和lambda将代码缩减为一个函数:
template<typename... ADDTHIS>
BSTR ConcatBstr(BSTR* dest, ADDTHIS... addthis)
{
// use static_assert to get a more descriptive error message
static_assert((std::is_same_v<ADDTHIS, BSTR> && ...), "tried to concant something else than BSTR");
UINT n = SysStringLen(*dest);
// use fold expression to sum up string lenghts
SysReAllocStringLen(dest, *dest, n + (SysStringLen(addthis) + ...));
// pointer to the next insertion
WCHAR* ptr = *dest + n;
// lambda appending the given string, incrementing ptr for the next invocation
auto append = [&ptr](BSTR src)
{
UINT n = SysStringLen(src);
memcpy(ptr, src, n * sizeof(*ptr));
ptr += n;
};
// use fold expressions to call `append` for every argument from left to right
(append(addthis), ...);
// append the zero terminator
*ptr = L'\0';
return *dest;
}
请注意,lambda正在通过引用捕获插入ptr
,因此每个调用都将使用上一个调用的增量值。