See the question and my original answer on StackOverflow

Although this works at compile time:

class CLX : public winrt::Microsoft::UI::Xaml::Resources::CustomXamlResourceLoader
{
    winrt::Windows::Foundation::IInspectable GetResource(const winrt::param::hstring& resourceId, const winrt::param::hstring& objectType, const winrt::param::hstring& propertyName, const winrt::param::hstring& propertyType) const 
    {
        return winrt::box_value(L"hello");
    }
};

The GetResource method won't be called as it's "just" a C++ method (that's why you get "Markup extension could not provide value" the error, because the method is never called) while the built-in CustomXamlResourceLoader implements this method as a method of the ICustomXamlResourceLoaderOverrides COM interface (which CustomXamlResourceLoader implements).

C++/WinRT provides a generated utility class for all WinRT types called [Type]T to wrap all this COM plumbing, ie: it will make sure your class implements GetResource at COM level so it's visible by external (to your project) pieces of code that only know COM exposure. This [Type]T is used everywhere in C++/WinRT samples for example in Author APIs with C++/WinRT but it would deserve its own chapter IMHO...

So it will work if you declare it like this instead:

struct CLX : winrt::Microsoft::UI::Xaml::Resources::CustomXamlResourceLoaderT<CLX>
{
  IInspectable GetResource(const hstring& resourceId, const hstring& objectType, const hstring& propertyName, const hstring& propertyType) const
  {
    return winrt::box_value(L"hello");
  }
};

And instantiate like this:

void App::OnLaunched([[maybe_unused]] LaunchActivatedEventArgs const& e)
{
    auto clx = make<CLX>();
    winrt::Microsoft::UI::Xaml::Resources::CustomXamlResourceLoader::Current(clx);
    ...
}