惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
Google DeepMind News
Google DeepMind News
G
Google Developers Blog
Martin Fowler
Martin Fowler
MongoDB | Blog
MongoDB | Blog
月光博客
月光博客
Jina AI
Jina AI
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
D
DataBreaches.Net
V
V2EX
WordPress大学
WordPress大学
T
The Blog of Author Tim Ferriss
Last Week in AI
Last Week in AI
B
Blog
博客园 - 叶小钗
小众软件
小众软件
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
A
About on SuperTechFans
J
Java Code Geeks
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog

The Old New Thing

std::call_once vs. std::async - The Old New Thing Magic statics vs. std::call_once - The Old New Thing Why do Microsoft job levels start in the high 50's instead of starting at a sane number like 1? - The Old New Thing Why didn't Read­Directory­ChangesW provide a way to correlate the two sides of a rename operation? - The Old New Thing How can I remove the Close button from my window caption? - The Old New Thing Why is the x86 undefined instruction called ud2? Why 2? - The Old New Thing What algorithm did Windows XP use to choose your initial user picture? - The Old New Thing A sample use of the winstart.bat file in Windows 95 - The Old New Thing Why don't we allow stacks to be sparse, instead of forcing them to be contiguous? - The Old New Thing What happens if you change a window class's GCL_CB­WND­EXTRA? - The Old New Thing The case of the progress callback that never got called when progress happened - The Old New Thing The perils of binding to value types in XAML - The Old New Thing Microspeak: Funded / unfunded - The Old New Thing AWE does not require PAE, though PAE makes it much more useful - The Old New Thing On forcing all derived classes to implement a specific non-virtual method, part 1 - The Old New Thing In the product end game, every change carries significant risk, episode 2 - The Old New Thing Why didn't the Windows Entertainment Pack just run the MS-DOS version inside an emulator? - The Old New Thing Comparing the two holograms on the Windows 95 box - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function, practical exam - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function - The Old New Thing On wrapping a callable in a lambda that just calls it with the same parameters - The Old New Thing Why did the Microsoft Entertainment Pack for Windows have a special sticker announcing that it also had Tetris? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing Forcing an ARM64X executable to run as a specific architecture - The Old New Thing A little helper class for managing LPPROC_THREAD_ATTRIBUTE_LISTs - The Old New Thing The comments that go into code versus those that go into the pull request description - The Old New Thing The little-known winstart.bat batch file - The Old New Thing How can I perform a Copy­File&shy in unbuffered mode? - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 5 - The Old New Thing
On forcing all derived classes to implement a specific no...
Raymond Chen · 2026-08-28 · via The Old New Thing

Last time, we observed that one way to force all derived classes to implement a specific non-virtual method is simply not to implement it in the base class and sit back and wait for the compile-time fireworks. I noted that we can do better than this, though.

The problem is that the compiler tells you what is wrong, but the details are often buried in the “supplementary error information”, and it may not be obvious how to dig it out, or maybe you dig it out but you don’t understand how to fix it.

You can steer people to the correct error by implementing the method as deleted.

// C++/WRL

struct OneWayConverter
{
    // Derived classes must implement Convert()
    HRESULT STDMETHODCALLTYPE Convert(IInspectable* value,
        ABI::Windows::UI::Xaml::Interop::TypeName targetType,
        IInspectable* parameter, HSTRING language,
        IInspectable** result) = delete;

    // One-way converters cannot convert back
    HRESULT STDMETHODCALLTYPE ConvertBack(IInspectable* /*value*/,
        ABI::Windows::UI::Xaml::Interop::TypeName /*targetType*/,
        IInspectable* /*parameter*/, HSTRING /*language*/,
        IInspectable** result)
    {
        *result = nullptr;
        return E_NOTIMPL;
    }
};

// C++/WinRT

struct OneWayConverter
{
    // Derived classes must implement Convert()
    winrt::Windows::Foundation::IInspectable
        Convert(
            winrt::Windows::Foundation::IInspectable const& /*value*/,
            winrt::Windows::UI::Xaml::Interop::TypeName const& /*targetType*/,
            winrt::Windows::Foundation::IInspectable const& /*parameter*/,
            winrt::hstring const& /*language*/) = delete;

    // One-way converters cannot convert back
    winrt::Windows::Foundation::IInspectable
        ConvertBack(
            winrt::Windows::Foundation::IInspectable const& /*value*/,
            winrt::Windows::UI::Xaml::Interop::TypeName const& /*targetType*/,
            winrt::Windows::Foundation::IInspectable const& /*parameter*/,
            winrt::hstring const& /*language*/)
    {
        throw winrt::hresult_not_implemented();
    }
};

// Plain C++ analogous scenario

struct OneWayConverter
{
    // Derived classes must implement Convert()
    Color Convert(Widget const&amp /*value*/) = delete;

    // One-way converters cannot convert back
    Widget ConvertBack(Color const& /*color*/)
    {
        throw std::exception("not implemented");
    }
};

This has a few benefits.

One is that the developer can see the exact function signature that they need to implement: It’s the one that got deleted in the base class.

Another is that the error message takes them to the deleted function, and if they go to that line of code, they will see the comment that explains why it is deleted.

winrt\windows.ui.xaml.data.h(1469,90): error C2280: 'winrt::Windows::Foundation::IInspectable OneWayConverter::Convert(const winrt::Windows::Foundation::IInspectable &,const winrt::Windows::UI::Xaml::Interop::TypeName &,const winrt::Windows::Foundation::IInspectable &,const winrt::hstring &)': attempting to reference a deleted function
      see declaration of 'OneWayConverter::Convert'
      test.cpp(60,9):
      'winrt::Windows::Foundation::IInspectable OneWayConverter::Convert(const winrt::Windows::Foundation::IInspectable &,const winrt::Windows::UI::Xaml::Interop::TypeName &,const winrt::Windows::Foundation::IInspectable &,const winrt::hstring &)': function was explicitly deleted
      ⟦ other error message spew the same as before ⟧

Starting in C++26, you can do even better yet: You can put a custom message directly in the delete!

struct OneWayConverter
{
    // Derived classes must implement Convert()
    winrt::Windows::Foundation::IInspectable
        Convert(
            winrt::Windows::Foundation::IInspectable const& /*value*/,
            winrt::Windows::UI::Xaml::Interop::TypeName const& /*targetType*/,
            winrt::Windows::Foundation::IInspectable const& /*parameter*/,
            winrt::hstring const& /*language*/)
        = delete("If you derive from OneWayConverter, you must implement Convert()");

    // One-way converters cannot convert back
    winrt::Windows::Foundation::IInspectable
        ConvertBack(
            winrt::Windows::Foundation::IInspectable const& /*value*/,
            winrt::Windows::UI::Xaml::Interop::TypeName const& /*targetType*/,
            winrt::Windows::Foundation::IInspectable const& /*parameter*/,
            winrt::hstring const& /*language*/)
    {
        throw winrt::hresult_not_implemented();
    }
};

The Microsoft Visual C++ compiler doesn’t support this feature yet, but other compilers do, and they include the custom message in the primary error text.

// clang
error: attempt to use a deleted function: If you derive from OneWayConverter, you must implement Convert()

// gcc
error: use of deleted function 'winrt::Windows::Foundation::IInspectable OneWayConverter::Convert(winrt::Windows::Foundation::IInspectable const&,winrt::Windows::UI::Xaml::Interop::TypeName const&,winrt::Windows::Foundation::IInspectable const&,winrt::hstring const&)': If you derive from OneWayConverter, you must implement Convert()

While this works for C++/WinRT and plain C++, it doesn’t work for C++/WRL because WRL derives from the abstract base class, and you cannot delete a method implemented by a base class. (Presumably because the method is still callable by casting to the base class.)

So the delete trick works only if your declaration is not an override of a base class declaration.

Tweaking the implementation to provide better compiler error messages is another example of compiler error message metaprogramming, which is one of the under-appreciated aspects of authoring a code library.

Category

Topics

Author

Raymond Chen

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.