首页 > 解决方案 > 使用 iostream (std::wcout) 打印 CComBSTR

问题描述

以下代码

#include <iostream>
#include <atlstr.h>

int main()
{
    CComBSTR bstr(L"test");
    std::wcout << bstr << std::endl;
    std::wcout << static_cast<BSTR>(bstr) << std::endl;
}

印刷

033FA16C
测试

我试图用调试器调查每种情况下发生了哪些转换,但两次都进入了operator BSTR. 那么为什么第一行打印地址而第二行打印文本呢?

标签: c++comiostreamatl

解决方案


我们可以从中完全删除 ATL,因为这实际上是一个如何wcout工作的问题。

考虑以下最小示例:

#include <iostream>

struct Foo
{
    operator const wchar_t*() const { return L"what"; };
};

int main()
{
    Foo f;
    std::wcout << f << std::endl;
    std::wcout << (const wchar_t*)f << std::endl;
}

// Output:
//   0x400934
//   what

现场演示

In your example, the implicit conversion from CComBSTR to BSTR is triggered, but not by the template that instantiates operator<<(const wchar_t*) (because the conversion is "user-defined", and user-defined conversions are not considered for template parameter matching). The only viable candidate then is the non-template operator<<(const void*), to which your converted BSTR is passed.

There's actually a proposal to "fix" this in the standard (LWG 2342) and the text of the proposal explains this in more detail.

In summary:

For wide streams argument types wchar_t const* and wchar_t are supported only as template parameters. User defined conversions are not considered for template parameter matching. Hence inappropriate overloads of operator<< are selected when an implicit conversion is required for the argument, which is inconsistent with the behavior for char const* and char, is unexpected, and is a useless result.

The only remaining viable overload is the one taking const void* and, since every pointer can implicitly convert to const void*, that's what you're getting.


推荐阅读