microsoft / cppwinrt

C++/WinRT
MIT License
1.64k stars 238 forks source link

Simplify static lifetime implementation #1300

Closed JaiganeshKumaran closed 1 year ago

JaiganeshKumaran commented 1 year ago

When component optimisations are enabled, to have a static lifetime factory and define the static methods in the factory, rather than the implementation type, you need to write static forwarders in the implementation type as shown here: https://learn.microsoft.com/en-us/uwp/cpp-ref-for-winrt/static-lifetime#examples.

Consider making the generated code in g.cpp call into the factory directly if the static_lifetime marker is present instead of calling the static method on the implementation type.

kennykerr commented 1 year ago

The relationship between optimizations and static factories is regrettably complex but isn't something we can easily fix without a major overhaul.

JaiganeshKumaran commented 1 year ago

Could you provide a generated base class for the implementation type that will automatically call into the factory instead? Obviously, with this, the factory needs to be defined first, which isn't a problem for static classes (can specify the factory instead as the second template parameter of factory_implementation::YourTypeT) but won't work for classes that can be instantiated.

JaiganeshKumaran commented 11 months ago

Here's a simple solution.


namespace winrt::Component
{
    template <int = 0>
    static auto GetObjectHelperStatics()
    {
        if constexpr (winrt::impl::has_static_lifetime_v<factory_implementation::Foo>)
        {
            return winrt::make_self<factory_implementation::Foo>();
        }
        else
        {
            // statics_type will be a new alias on the factory based on FooT's second template parameter.
            // Will cause undefined behaviour if the methods that are supposed to be static are not.
            // But that cannot be the case since the factory type does T::StaticMethod()
            // And that cannot work unless the method is actually static as long as T is not the same as the factory type.
            return std::add_pointer_t<factory_implementation::Foo::statics_type>{ nullptr };
        }
    }

    void Foo::StaticMethod()
    {
        // Before
        return implementation::Foo::StaticMethod();
        // After.
        return GetObjectHelperStatics()->StaticMethod();
    }
}