Skip to content

Deducing this for delegates#1553

Open
YexuanXiao wants to merge 7 commits into
microsoft:masterfrom
YexuanXiao:deducting-this-upstream
Open

Deducing this for delegates#1553
YexuanXiao wants to merge 7 commits into
microsoft:masterfrom
YexuanXiao:deducting-this-upstream

Conversation

@YexuanXiao
Copy link
Copy Markdown
Contributor

@YexuanXiao YexuanXiao commented Mar 23, 2026

When using lambda coroutines as delegates, care must be taken that the lifetime of captured objects may be shorter than that of the coroutine, see #766 (comment). This issue has a better solution in C++23, which is to use explicit object parameters to copy the captures into the coroutine frame. However, this feature is currently not available in C++/WinRT.

The following code fails to compile with an error that the copy constructor has been deleted.

#include <winrt/Windows.Foundation.Collections.h>
using namespace winrt::Windows::Foundation::Collections;

int main()
{
	int called{};
	int sum{};

	auto vector = winrt::single_threaded_observable_vector<int>();
	auto revoker = vector.VectorChanged(winrt::auto_revoke, 
		[called, sum](this auto, IObservableVector<int>, IVectorChangedEventArgs)
		{
		});
}

The reason is that the final type delegate inherits from the handler (lambda), and code_writers.h#L2619 uses the type delegate (*this in the Invoke member function of delegate) to call operator(), causing this (explicit parameter of lambda) to be deduced as delegate. Since delegate is non-copyable, operator() cannot be called. This change makes Invoke use the original lambda's type to call operator(), so this is deduced as the lambda's type, resolving the issue.

Because of the purpose is to copy the captured object into the coroutine frame, the slicing that occurs here is intentional, and there is no need to copy the complete delegate object.

Comment thread run_tests.cmd Outdated
Comment thread build_test_all.cmd Outdated
Comment thread test/CMakeLists.txt Outdated
@YexuanXiao
Copy link
Copy Markdown
Contributor Author

YexuanXiao commented Mar 23, 2026

I found that when running the CI on my own fork, Clang 20 target x86 generated incorrect code, causing the test to fail. The characteristic of this bug is that in the constructor of observed_sender at L101, this is observed to be X, while in the assignment operator at L108, this is observed to be X+16 (in bytes). Therefore, this is undoubtedly a Clang bug rather than a test bug. As a result, I will disable the test observablevector_vectorchanged for Clang target x86.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a C++23 “deducing this” compatibility issue for C++/WinRT delegates by ensuring the upcall invokes the underlying handler type (lambda) rather than the non-copyable delegate wrapper type. It also adds a dedicated C++23 test target to validate the behavior in CI and local builds.

Changes:

  • Update delegate invocation codegen/runtime to call operator() via static_cast<H&>(*this) so this auto deduces as the handler type.
  • Add a new test_cpp23 test project (MSBuild + CMake) and wire it into scripts/CI.
  • Adjust Catch2 UDL declarations to the standard-conforming operator ""_suffix spelling (needed for newer language modes).

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
cppwinrt/code_writers.h Changes generated delegate Invoke upcall to use static_cast<H&>(*this) for correct this auto deduction.
strings/base_delegate.h Updates runtime delegate invoke path to call through the handler subobject (H) rather than the wrapper.
test/test_cpp23/delegate_deducing_this.cpp Adds C++23 tests covering delegates/handlers using explicit object parameters (this auto).
test/test_cpp23/main.cpp New Catch2 test runner for the C++23 test target.
test/test_cpp23/pch.h New PCH header for the C++23 test target.
test/test_cpp23/pch.cpp New PCH source for the C++23 test target.
test/test_cpp23/CMakeLists.txt Adds CMake build definition for test_cpp23.
test/test_cpp23/test_cpp23.vcxproj Adds MSBuild project for test_cpp23 targeting latest C++ mode / C++23 projection setting.
test/CMakeLists.txt Wires test_cpp23 into the test CMake build.
test/catch.hpp Fixes user-defined literal operator spelling to standard ""_suffix form.
.github/workflows/ci.yml Adds test_cpp23 to the Windows test matrix.
cppwinrt.sln Adds the new test_cpp23 project to the solution.
build_test_all.cmd Builds test_cpp23 as part of the “build all tests” script.
run_tests.cmd Runs test_cpp23 as part of the test runner script.

Comment thread test/test_cpp23/test_cpp23.vcxproj Outdated
YexuanXiao and others added 3 commits May 22, 2026 13:59
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants