'Casting TObject to TMenuItem and retrieving caption adds & to string

So I have some really simple code below. I am using this function in multiple onclick events to pass in the TMenuItems's caption.

procedure TForm1.BtnClick(Sender: TObject);
begin
 TestFrm.MyVar:= TMenuItem(Sender).Caption;
 InteractiveSchedulerFrm.ShowModal;
end;

However, the result of this is that the TestFrm.MyVar field ends up having an ampersand included in it that wasn't originally there, and its always in a seemingly random spot.

I have temporarily patched the issue by replacing all ampersands in the string, but I am mostly curious as to whats causing the ampersand to be placed in the string.

Example:

TMenuItem(Sender).Caption = 'TEST';

TestFrm.MyVar = 'TE&ST' or '&TEST' etc



Solution 1:[1]

The ampersands in TMenuItem captions are used to indicate keyboard shortcuts to the Menu items. The ampersand appears before the shortcut character and underlines the character in some cases to ensure the user knows about the shortcut. This type of character is called an accelerator character.

For example, a TMenuItem with a caption of &TEST could be triggered with an ALT+T keypress, while a TMenuItem with a caption of TE&ST could be triggered with an ALT+S keypress.

If you want an ampersand to appear in your menu item caption, you will need to escape it with another ampersand (e.g. Bacon && Eggs). Here is a link to the first source I found about this feature.

Solution 2:[2]

The central problem you're encountering is that you have a type template parameter whose type you want to be constrained to being some specialization of some template. That's not a thing you can do with a requires clause. At least, not easily.

It's best to avoid this problem. You're only encountering it because you insist that sum's template parameter must be some specialization of IntList instead of the integers themselves directly. The best way to handle this is by ditching this assumption:

template<int... Ints>
constexpr int sum(IntList<Ints...>)
{ return (0 + ... + Ints); }

You then call this function as so: sum(IntList<1, 2>{}). Note that IntList needs to have a constexpr default constructor.

Solution 3:[3]

Your definition of the concept of IsIntList is wrong, it only evaluates the value of IntList<N...>{}, and since IntList is not a bool type, IsIntList always return false.

You should use template partial specialization to define the IsIntList.

template<int...N>
class IntList;

template<class T>
inline constexpr bool IsIntList = false;
template<int...N>
inline constexpr bool IsIntList<IntList<N...>> = true;

For a specialized version of the sum, just constrain IsIntList<T> to be true, then you can extract the value of the IntList with the help of a tag class and template lambda to calculate the sum.

template<class>
struct tag{};

template<class T>
  requires IsIntList<T>
int sum() {
  return []<int...N>(tag<IntList<N...>>) 
    { return (N + ... + 0); }(tag<T>{});
}

Demo.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 crash
Solution 2
Solution 3