【问题标题】:Printing CComBSTR with iostream (std::wcout)使用 iostream (std::wcout) 打印 CComBSTR
【发布时间】:2020-01-20 16:00:17
【问题描述】:

以下code

#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。那么为什么第一行打印地址而第二行打印文本呢?

【问题讨论】:

  • std::wcout 不知道有关 CComBSTR 的 bean,而智能类型不知道有关 iostream 的 bean。 BSTR 变得更加智能,因为它是 wchar_t* 的别名的别名。不够聪明,因为 BSTR 可以存储嵌入的 \0。这并不常见到需要担心。
  • Beans 并不真正相关; OP 合理地期望隐式转换开始。

标签: c++ com iostream atl


【解决方案1】:

我们可以从中完全删除 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

(live demo)

在您的示例中,the implicit conversionCComBSTRBSTR 被触发,但不是由实例化operator&lt;&lt;(const wchar_t*) 的模板触发(因为转换是“用户定义的”,并且模板参数匹配不考虑用户定义的转换)。那么唯一可行的候选者是非模板operator&lt;&lt;(const void*),您转换的BSTR 将传递给它。

在标准 (LWG 2342) 中实际上有一个“修复”这个问题的提议,并且该提议的文本更详细地解释了这一点。

总结:

对于宽流参数类型 wchar_t const*wchar_t 仅支持作为模板参数。模板参数匹配不考虑用户定义的转换。因此,当参数需要隐式转换时,会选择不适当的 operator&lt;&lt; 重载,这与 char const*char 的行为不一致,是意外的,并且是无用的结果。

唯一剩余的可行重载是采用const void* 的重载,并且由于每个指针都可以隐式转换为const void*,这就是你得到的。

【讨论】:

  • >你说是,但不是。 -- 它是由一个“错误的”重载触发的:operator
  • @vkrzv 关闭。您说“两次都进入了运营商BSTR”,但除非发生奇怪的事情,否则这不可能是真的:)因为根本不应该触发转换。 “模板参数匹配不考虑用户定义的转换。”采用const wchar_t*的重载来自模板。
  • 但是const void*非模板重载也能触发operator BSTR。否则它是从哪里得到地址的?
猜你喜欢
  • 2020-11-05
  • 1970-01-01
  • 1970-01-01
  • 2011-12-18
  • 1970-01-01
  • 2013-03-09
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
相关资源
最近更新 更多