M.M
M.M

Reputation: 141618

Is there a way to write a BSTR literal?

When calling a function that expects a BSTR it'd be nice to be able to write something like:

iFoo->function( bs"HELLO" );

However the only workaround I'm aware of is to use a wrapper that calls SysAllocString etc., e.g.:

iFoo->function( WideString(L"HELLO").c_bstr() );

which is kind of ugly. Is there actually such an option to create a BSTR literal?

Motivation: easier-to-read code, and faster runtime performance by avoiding an allocation and deallocation.

Clarification: I am only talking about situations where the caller (i.e. us) has ownership of the BSTR, for example: calling a function that takes a BSTR [in] parameter. Of course, it would be silly to supply a pointer to a BSTR literal to a function which will go on to try and free the string.

Upvotes: 6

Views: 2144

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 596547

To follow up on @MSalters's answer, a custom user-defined literal could look something like this:

CComBSTR operator "" _bstr (const char* str, std::size_t len)
{
    return CComBSTR(len, str);
}

Then you can do this (as CComBSTR has a BSTR conversion operator defined):

iFoo->function( "HELLO"_bstr );

You can even overload the operator for multiple input string literal types:

CComBSTR operator "" _bstr (const wchar_t* str, std::size_t len)
{
    return CComBSTR(len, str);
}

CComBSTR operator "" _bstr (const char16_t* str, std::size_t len)
{
    return CComBSTR(len, (wchar_t*)str);
}

iFoo->function( L"HELLO"_bstr ); // calls wchar_t* version with UTF-16 encoded data

iFoo->function( u"HELLO"_bstr ); // calls char16_t* version with UTF-16 encoded data

iFoo->function( u8"HELLO"_bstr ); // calls char* version with UTF-8 encoded data...

Note the last case. Since the operator will not know whether it is being passed ANSI or UTF-8 data, and CComBSTR assumes ANSI when passed char* data, you should use a different literal suffix to differentiate so you can convert the UTF-8 correctly, eg:

CComBSTR operator "" _utf8bstr (const char* str, std::size_t len)
{
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> conv;
    std::wstring wstr = conv.from_bytes(std::string(str, len));
    return CComBSTR(wstr.length(), wstr.c_str());
}

iFoo->function( u8"HELLO"_utf8bstr );

Upvotes: 4

MSalters
MSalters

Reputation: 179907

User defined literals would be the way to go:

"HELLO"_bstr calls template<char...> BSTR operator "" _bstr ( const char*, std::size_t) which can then call SysAllocString()

New in VS14.

[edit]

Based on the comments, it might be better to return a _bstr_t or other class which takes ownership of the SysAllocString() result and implicitly converts to BSTR. This temporary will be destroyed at the end of the full expression, and therefore after iFoo->function( "HELLO"_bstr ); returns.

Upvotes: 4

Related Questions