std::function
?“Proxy” is a single-header, cross-platform C++20 template library for modern runtime polymorphism based on pointer-semantics. Similar with C++ virtual functions, it generates indirect functions behind the scenes at compile-time but does not require inheritance. It also has GC-like behavior that allows different objects of the same proxy
type to have different lifetime models without requiring runtime GC overhead.
“Proxy” is built by engineers at Microsoft and initially deployed in the Windows operating system. For 40 years, the inheritance-based polymorphism paradigm has been the only scalable solution for runtime polymorphism in C++. However, a “virtual function” is no longer the optimal choice for runtime polymorphism today, and new languages with better paradigms, like traits in Rust, are emerging. “Proxy” is our latest and greatest solution for generic runtime polymorphism in C++. It is easy to integrate and makes C++ feel like a brand new language when dealing with runtime abstractions.
We encourage every C++ developer to use this library for production, including in embedded engineering scenarios. Before deciding to write any virtual function, consider whether using “Proxy” could simplify the architecture.
While virtual functions have served well for decades, “Proxy” offers modern solutions that can lead to better performance, easier maintenance, and more flexible code design when it comes to runtime abstraction.
The fundamental abstraction of “Proxy” is called “facade”. It is recommended for beginners to start with the examples in the README, try to understand the pattern of defining a facade
type, using a facade type to specify a proxy
type, and creating and using a proxy object at runtime. Don’t hesitate to consult the specifications for more details about any facility in the library.
Since “Proxy” is a single-header library, you can simply navigate to the latest release, download the source code, and include “proxy.h” in your project. Make sure your compiler version meets the minimum requirements for compilers. If your project has already integrated with vcpkg or conan, just search for the keyword “proxy” and install it. Thanks to the community that helped port “Proxy” to these platforms!
Follow the 4 steps below to upgrade an existing project from using virtual functions to “Proxy”:
facade
types that match the “base classes with virtual functions” (virtual base classes).proxy
from the API boundary.The design of “Proxy” follows the zero-overhead principle. With general compiler optimizations, “Proxy” is expected to generate high quality code in most scenarios that is not worse than an equivalent hand-written implementation with or without virtual functions. In practice, when a construct of runtime abstraction has ownership of its context, “Proxy” usually has better performance than the inheritance-based approach in lifetime management. When performing an indirect call, “Proxy” usually generates similar code to a virtual function with equal performance. We have observed that when the concrete implementation and the abstraction appear in the same translation unit, a virtual function is more likely to be devirtualized in the generated code, but sometimes the compiler won’t do that trick for “Proxy”.
At the beginning, we explored the feasibility of designing a general-purpose polymorphic wrapper based on value semantics, just like std::function
and std::move_only_function
. It is technically feasible, but not as good as those languages with GC like C# or Java in terms of usability. We had a hard time refining the theory of OOP and finally realized that indirection is the nature of computer science, and decided to leverage the concept of pointer in C++ as the basis of “Proxy”.
“Proxy” defines 4 macros: __msft_lib_proxy
, PRO_DEF_MEM_DISPATCH
, PRO_DEF_FREE_DISPATCH
, and PRO_DEF_WEAK_DISPATCH
. __msft_lib_proxy
is the feature test macro, following the existing practice in the C++20 standard. The other 3 macros are fundamental facilities to define a custom dispatch
type. These macros cannot be replaced by modern C++ facilities because there is no existing language feature prior to C++26 that allows generating a function with an arbitrary name. As a result, “Proxy” does not provide a default interface for modules as of now.
Currently, there is an ongoing proposal being reviewed in the ISO C++ committee. The progress can be tracked here.
Please search for your scenario in the existing issues first, and feel free to file an a new one on demand, following the Microsoft Open Source Code of Conduct.