Description
Describe the bug
In 2023, the C++ Subsystem::SetDefaultCommand
function could accept an l-value reference to a command variable. However, the new usage of concepts breaks this use-case.
The function previously used std::enable_if_t<std::is_base_of_v<Command, std::remove_reference_t<T>>>
to check if the type passed in was a subclass of Command, accepting both l-value and r-value references. Now, the function uses the concept std::derived_from<Command> T
, which does not remove the reference. As a result, passing in an l-value reference results in std::derived_from<T&, Command>
, and std::is_base_of_v<Command, T&> == false
.
To Reproduce
Steps to reproduce the behavior:
- Construct a RunCommand
m_defaultCommand
(any subclass of command also works) as a member variable of RobotContainer. - Construct a subsystem
m_subsystem
as a member variable of RobotContainer. - In the RobotContainer subsystem, call
m_subsystem.SetDefaultCommand(m_defaultCommand);
. This does not compile.
Expected behavior
This example should compile, just as it did in 2023 WPILib.
Screenshots
n/a
Desktop (please complete the following information):
- OS: Windows 11
- Project Information:
WPILib Information:
Project Version: 2024.1.1-beta-1
VS Code Version: 1.83.1
WPILib Extension Version: 2024.1.1-beta-1
C++ Extension Version: 1.17.5
Java Extension Version: 1.23.0
Java Debug Extension Version: 0.52.0
Java Dependencies Extension Version 0.23.0
Java Version: 17
Java Location: C:\Users\Public\wpilib\2024\jdk
Vendor Libraries:
WPILib-New-Commands (1.0.0)
Additional context
One possible solution is to define a concept that handles this:
namespace wpi {
template <class Derived, class Base>
concept ref_derived_from = std::derived_from<std::remove_reference_t<Derived>, Base>;
}
Another solution is to use something like requires std::derived_from<std::remove_reference_t<T>, Command>
instead.