My initial reaction to seeing the aggregate in your default value for pair_in was that there were too many 'others', so I independently wrote one using the record type declaration itself:
library ieee;
use ieee.std_logic_1164.all;
package some_record is
type ifx_t is
record
data : std_logic_vector(127 downto 0);
address : std_logic_vector (19 downto 0);
WrReq : std_logic;--
RdReq : std_logic; --
end record;
type Array_ifx_t is array (0 to 2) of ifx_t;
-- positional association in an aggregate used for initialization:
signal pair_in: ifx_t := ((others => '0'), (others => '0'),'0','0');
end package;
And this analyzed successfully. An aggregate has two types of association, positional or named. The above default value expression is positional. With a named association:
signal pair_in: ifx_t := -- named association of record elements:
(
data => (others => '0'),
address => (others =>'0'),
WrReq => '0',
RdReq => '0'
);
You'll notice this bears an uncanny resemblance to the value expression found in Morten's accepted answer's constant declaration, and actually tells the story of compatibility for an aggregate expression.
An aggregate compatible with a record type contains a value expression that is compatible with each element of the record type. This is done for the array elements data and address by providing aggregates for their default values, while WrReq and RdReq are provided with their default values directly.
The extra others statement found in the original attempt would have been appropriate had pair_in
been a composite type comprised of an array comprised of ifx_t
record type elements.
The LRM (e.g. IEEE Std 1076-1993) has a section on Expressions, a subsection on Aggregates with a further subsection on Record aggregates.
There's also a section on Types, a subsection on Composite types, with a further subsection on Record types.