Печать CComBSTR с помощью iostream (std :: wcout) - PullRequest
1 голос
/ 19 сентября 2019

Следующий код :

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

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

отпечатки

033FA16Ctest

Я пытался выяснить, какие преобразования выполняются в каждом случае с помощью отладчика, но оба раза вступили в operator BSTR.Так почему первая строка печатает адрес, а вторая печатает текст?

1 Ответ

1 голос
/ 19 сентября 2019

Мы можем полностью удалить 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)

В вашем примере неявное преобразование из CComBSTR в BSTR инициируется, но не по шаблону, который создает экземпляр operator<<(const wchar_t*)(потому что преобразование является «определяемым пользователем», и определяемые пользователем преобразования не учитываются при сопоставлении параметров шаблона).Тогда единственным приемлемым кандидатом является не шаблон operator<<(const void*), в который передается ваш преобразованный BSTR.

На самом деле есть предложение «исправить» это в стандарте ( LWG 2342 ) и текст предложения объясняет это более подробно.

В итоге:

Для широких потоков типы аргументов wchar_t const* и wchar_t поддерживаются только в качестве параметров шаблона,Определенные пользователем преобразования не учитываются при сопоставлении параметров шаблона.Следовательно, неподходящие перегрузки operator<< выбираются, когда для аргумента требуется неявное преобразование, которое не согласуется с поведением для char const* и char, является неожиданным и бесполезным результатом.

Единственная оставшаяся жизнеспособной перегрузка - это та, которая принимает const void*, и, поскольку каждый указатель может неявно преобразовывать в const void*, это то, что вы получаете.

...