none
ComPtrクラスが使えない

    質問

  • msxmlを使用してxmlの書き込みプログラムを書いたのですが、ComPtrを使うと、Windows SDK 10.0.16299.0以外ではビルドエラーが出てしまい、全くビルドできなくて困っています。

    私のPCにはWindows SDK 10.0.16299.0以外にも10.0.15063.0、10.0.14393.0、Windows 8.1のSDKが入っており、10.0.15063.0と10.0.14393.0ではC2760のみ、8.1ではC2059、C2143、C2334、C2760、C2833、C4430の6つが出てきます。

    ビルドエラーの発生しているのがclient.hと出てきてしまっており、また、Visual Studioで修復をかけてもダメなので全く対処法が分からない状態です。

    どのようにすれば良いのでしょうか?

    環境:Visual Studio 2017 Community

    ちなみにソースコードは

    https://github.com/Shirley-Chan/GetGPU/tree/master/GetGPU/ExeVersion

    にあります。

    以下に画像のURLを添付します。

    Windows 10 SDKでのビルド時のエラー

    https://photos.app.goo.gl/m2jDAwb4QSXmzg4x2

    Windows 8.1 SDKでのビルド時のエラー

    https://photos.app.goo.gl/Et3WKQjixwbZXBBG3

    2018年3月23日 16:12

回答

  • Visual C++ 2017 コンパイラとしての互換性の問題…かな?

    10.0.16299.0\winrt\wrl\client.h

    static_assert(__is_base_of(IUnknown, typename T::InterfaceType), "T has to derive from IUnknown");

    10.0.15063.0\winrt\wrl\client.h

    static_assert(__is_base_of(IUnknown, T::InterfaceType), "T has to derive from IUnknown");
    このように新しいヘッダーファイルでは typename キーワードが入っています。
    15603.0 を Visual C++ 2015 コンパイラーでコンパイルすると通るので、そういう事情なのでしょう。

    (古いヘッダーファイルは Visual C++ 2017 のコンパイラで使えない)

    // 互換オプションがあるかどうかは調べていません。

    2018年3月23日 21:23
    モデレータ
  • 結論からいうと /permissive- (Standards conformance) オプションを外してみてください。原因はAzuleanさんが指摘されている通りです。

    C++言語では解釈が曖昧になる個所には typename キーワードを前置する仕様です。ところがVisaul C++では歴史的に推測可能な個所ではtypenameキーワードを省略可能な独自拡張を行っていました。しかし近年、C++言語仕様に従うよう強化され、なおかつVisual Studioでプロジェクト作成を行うと /permissive- (Standards conformance) オプションが有効化されることにより、その強化が有効化されるようになりました。
    これにより、従来 typenameキーワードが省略されていてもコンパイルできていたコードが「言語仕様に準拠していない」とエラー検出されるようになっています。
    # 皮肉なことにC++言語の次バージョンでtypenameを省略可能にしようと議論されていますw

    それとは別に8.1ではソースコードの問題でビルドできなさそうです。GPUInformationコンストラクターが2引数なのにもかかわらず、3引数で呼び出しているのでどうにもなりません。

    • 回答としてマーク shirley-chan 2018年3月24日 2:04
    2018年3月23日 23:11

すべての返信

  • Visual C++ 2017 コンパイラとしての互換性の問題…かな?

    10.0.16299.0\winrt\wrl\client.h

    static_assert(__is_base_of(IUnknown, typename T::InterfaceType), "T has to derive from IUnknown");

    10.0.15063.0\winrt\wrl\client.h

    static_assert(__is_base_of(IUnknown, T::InterfaceType), "T has to derive from IUnknown");
    このように新しいヘッダーファイルでは typename キーワードが入っています。
    15603.0 を Visual C++ 2015 コンパイラーでコンパイルすると通るので、そういう事情なのでしょう。

    (古いヘッダーファイルは Visual C++ 2017 のコンパイラで使えない)

    // 互換オプションがあるかどうかは調べていません。

    2018年3月23日 21:23
    モデレータ
  • 結論からいうと /permissive- (Standards conformance) オプションを外してみてください。原因はAzuleanさんが指摘されている通りです。

    C++言語では解釈が曖昧になる個所には typename キーワードを前置する仕様です。ところがVisaul C++では歴史的に推測可能な個所ではtypenameキーワードを省略可能な独自拡張を行っていました。しかし近年、C++言語仕様に従うよう強化され、なおかつVisual Studioでプロジェクト作成を行うと /permissive- (Standards conformance) オプションが有効化されることにより、その強化が有効化されるようになりました。
    これにより、従来 typenameキーワードが省略されていてもコンパイルできていたコードが「言語仕様に準拠していない」とエラー検出されるようになっています。
    # 皮肉なことにC++言語の次バージョンでtypenameを省略可能にしようと議論されていますw

    それとは別に8.1ではソースコードの問題でビルドできなさそうです。GPUInformationコンストラクターが2引数なのにもかかわらず、3引数で呼び出しているのでどうにもなりません。

    • 回答としてマーク shirley-chan 2018年3月24日 2:04
    2018年3月23日 23:11
  • お二方ともありがとうございます。/permissiveオプションを外したらビルドが通りました。

    Visual C++の独自拡張に起因するものだったんですね

    あと佐祐理さん、引数の件、ご指摘ありがとうございます。

    元々3引数のコンストラクタだったんですが、引数減らした時に最後の引数消すの忘れてました

    2018年3月24日 2:04
  • 作者さん自身による質問だったのですね、アカウント名を見ていませんでした orz

    いろいろ気になるところがありますが、ComPtrの使い方について間違っているので指摘しておきます。

    ComPtr<IXMLDOMElement> MSXMLWrite::CreateElementComPtr(const wchar_t* Tag) {
    	return ComPtr<IXMLDOMElement>(this->CreateElementNormalPtr(Tag));
    }

    とコンストラクターで呼び出していますが、これをやってしまうとコンストラクターによって1回余分にAddRefされてしまうため、COMオブジェクトが解放されなくなってしまいます。正しくはComPtr::Attachを使います。もしくは生ポインターで受けたりせず、直接ComPtrで受ける方が楽です。

    # そのためには _variant_t クラスと同様に _bstr_t クラスを使った方が楽だとか、MSXMLを使うならxmlliteの方がインデントもサポートしていて楽だとか…。

    2018年3月26日 7:39