限制用于连接BSTR的参数的类型

时间:2019-03-29 19:54:33

标签: c++ windows templates

所以我写了这个模板化的可变参数函数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()的属性的同时改进此代码?

1 个答案:

答案 0 :(得分:1)

A1 :不确定您的要求是什么,因为编译器已经拒绝任何传递不兼容类型的尝试,因为模板实例化有时会失败。但是您可以使用std::enable_ifstatic_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,因此每个调用都将使用上一个调用的增量值。