1. 程式人生 > >VS2017編譯WRL的Callback模版函式相容性問題及解決方法

VS2017編譯WRL的Callback模版函式相容性問題及解決方法

近來一直在研究DXR的示例程式碼,並在其中看到例子中大量的使用了WRL的新模版類代替ATL的老三樣的模版類,使用最多的就是COM智慧指標Microsoft::WRL::ComPtr類。在聚合使用D3D的介面時,更是像下面這樣大量應用該模版包裝了D3D的介面:

......
Microsoft::WRL::ComPtr<IDXGIFactory4>               m_dxgiFactory;
Microsoft::WRL::ComPtr<IDXGISwapChain3>             m_swapChain;
Microsoft::WRL::ComPtr<ID3D12Resource>              m_renderTargets[MAX_BACK_BUFFER_COUNT];
Microsoft::WRL::ComPtr<ID3D12Resource>              m_depthStencil;
// Presentation fence objects.
Microsoft::WRL::ComPtr<ID3D12Fence>                 m_fence;
UINT64                                              m_fenceValues[MAX_BACK_BUFFER_COUNT];
Microsoft::WRL::Wrappers::Event                     m_fenceEvent;
// Direct3D rendering objects.
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>        m_rtvDescriptorHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>        m_dsvDescriptorHeap;
......

使用ComPtr包裝這些介面的好處就不贅述了,我只是處於對新事物的強烈好奇與推崇,就試圖在自己的程式碼中也引用WRL中的模版類。於是我依葫蘆畫瓢在我的標頭檔案中加入了簡單的一句:

#include <wrl.h>

可是直接編譯卻報瞭如下莫名其妙的錯誤:

c:\program files (x86)\windows kits\10\include\10.0.17134.0\winrt\wrl\event.h(316): error C7510: “Callback”: 模板 從屬名稱的使用必須以“模板”為字首

c:\program files (x86)\windows kits\10\include\10.0.17134.0\winrt\wrl\event.h(324): error C7510: “Callback”: 模板 從屬名稱的使用必須以“模板”為字首

雙擊檢視程式碼如下:

template<typename TDelegateInterface, typename TLambda>
ComPtr<typename Details::DelegateArgTraitsHelper<TDelegateInterface>::Interface> Callback(TLambda&& callback) throw()
{
    using DelegateHelper = Details::DelegateArgTraitsHelper<TDelegateInterface>;
    return DelegateHelper::Traits::Callback<TDelegateInterface
        , typename DelegateHelper::Interface>(Details::Forward<TLambda>(callback));
}

從程式碼分析大概瞭解這個Callback的模版函式因為又使用了一個lambda函式的引數callback,但是上下文中的模版引數定義只是說這是個型別名,這樣在呼叫Callback的時候編譯器就不知道使用Callback的哪個具體模版了,但其實這是個偽錯誤,根本原因就是在VS2017中,VC++的編譯器預設打開了一個開關選項:/permissive-,具體如下圖所示:

這個選項的含義根據MSDN的說法是這樣:

/permissive-:啟用所有嚴格標準符合性編譯器選項,並禁用大部分特定於 Microsoft 的編譯器擴充套件(但有一些例外,比如 __declspec(dllimport))。 在 Visual Studio 2017 15.5 版中此選項預設為開啟狀態。 /permissive- 符合性模式包括對兩階段名稱查詢的支援。

當然一如既往的MSDN的這個解釋是看不懂的,但大意就是說這個開關開啟後好多語言擴充套件就不能用了,這也是為了適應跨平臺跨編譯器編譯Windows C++程式碼做的檢查。但是這個開關就攔住了WRL裡的上述Callback模版函式的呼叫,最終引起上述的哪個編譯錯誤。

知道了問題的癥結,那麼修改就不難了,只需要將這個開關關閉即可,如下圖:

最終點選確定,編譯,一次就通過了!當然後果可能就是對其他的C++編譯器來說可能就沒法編過了,當然我們使用的本來就是Windows的WRL模版類,推薦使用VC++編譯器,不相容就不相容吧。