No se puede acceder a los miembros de un parámetro genérico de ADA

StackOverflow https://stackoverflow.com/questions/2338913

  •  22-09-2019
  •  | 
  •  

Pregunta

Estoy tratando de escribir un paquete genérico y una de las operaciones requeridas es verificar los registros de datos recibidos en un bus. El tipo de registro variará y es un parámetro genérico. Sin embargo, cualquier intento de acceder a los miembros del parámetro genérico causa un error de compilación.

El error ... (ADA 95 Gnat 2009)

file.adb:XX no selector "Data" for private type "The_Transfer_Type" defined at file.ads:YY

La declaracion...

generic
  type The_Transfer_Type is private;
  SIZE : Integer;
package CC_Test_Channel is
  function Checksum(Msg : The_Transfer_Type) return Integer;
end package

Y el cuerpo ...

function Checksum(Msg : The_Transfer_Type) return Integer is
  Sum : Integer := 0;
begin
  -- calculate the checksum
  for i in 1 .. SIZE loop
    Sum := Sum + Integer(Msg.Data(i));
  end loop;
  return Sum;
end Checksum;
¿Fue útil?

Solución

Cuando especifica que un parámetro genérico es un tipo privado, bueno, ADA asume que lo dice en serio :-)

Es decir, no tienes acceso a sus componentes. Ada no lo es "Tipo de pato", Por lo tanto, es irrelevante si sabe o no que un tipo instanciador podría poseer un campo en particular (¿cómo esperaría que su función de suma de verificación funcione si el parámetro_TRANSFER_TYPE fuera instanciado con, por ejemplo, entero?)

Una forma de abordar esto es también suministrar una función de accesorios como un parámetro para el genérico que recuperará los datos necesarios para, en este caso, calcular la suma de verificación. P.ej:

generic
   type The_Transfer_Type is private;
   with function Get_Checksummable_Data_Item
           (Msg : The_Transfer_Type;
            I   : Integer) return Integer;
   SIZE : Integer;

package CC_Test_Channel is
   function Checksum(Msg : The_Transfer_Type) return Integer;
end CC_Test_Channel;

El cuerpo es entonces:

function Checksum(Msg : The_Transfer_Type) return Integer is
   Sum : Integer := 0;
begin
   -- calculate the checksum
   for i in 1 .. SIZE loop
      Sum := Sum + Get_Checksummable_Data(Msg, I);
   end loop;
   return Sum;
end Checksum;

La función que suministra para get_checksummable_data es específica para el_transfer_type y simplemente devuelve el valor seleccionado de los campos de componentes de The_Transfer_Type.

Hay una serie de otras formas de configurar esto también, como proporcionar un tipo de matriz sin restricciones como un parámetro formal genérico y una función formal para recuperarlo, esto también le permite deshacerse del parámetro formal de tamaño explícito. O puede escribir una función checksum () como una de las operaciones del tipo con el que está instanciando CC_TEST_CHANNEL, y luego tener:

with function Calculate_Checksum(Msg : The_Transfer_Type) return Integer;

como uno de los formales genéricos.

Retroceda y piense en las posibilidades ...

Otros consejos

(Me mudé de un comentario, ya que esto fue largo)

ADA (95 y posterior) admite corrientes. A diferencia de las transmisiones C ++, que son más o menos para la conversión de cadenas, Las transmisiones de ADA se entienden como un mecanismo general para realizar operaciones en datos (Típicamente E/S).

Cada objeto Ada tiene 'Write y 'Read atributos. Hay algunas transmisiones suministradas por el lenguaje (para E/S de archivo), pero también tiene la capacidad de crear la suya derivada de Ada.streams.root_stream_type. Si escribe su propia transmisión de esta manera, hay algunas rutinas de bajo nivel que le brindan acceso directo a los datos.

Esto le permite escribir sus propias transmisiones para realizar operaciones como E/S, compresión de datos, o en su caso, tal vez los datos de enchufación del bus antes de cargarlo en variables (a través de 'leer). Lo hice yo mismo en el pasado para implementar una funcionalidad de registro/reproducción para nuestro software en tiempo real. También lo busqué compresión una vez (terminamos sin necesitar la compresión).

generic 
  type The_Transfer_Type is private; 
  ...

El código anterior significa que el cliente puede proporcionar cualquier tipo que sueñe para The_Transfer_Type (siempre que no sea "limitado"). También significa que su genérico no sabe absolutamente nada sobre el tipo, excepto que la asignación está disponible.

Con los genéricos de ADA existe una especie de relación inversa entre cuántos tipos diferentes de objetos se pueden suministrar para un parámetro genérico y qué operaciones son disponibles para los genéricos en esos objetos. Por ejemplo, el tipo más abierto sería is limited private. Puede suministrar cualquier tipo de tipo para uno de esos. Sin embargo, el genérico no puede hacer casi nada con él. Incluso la tarea no estaría disponible.

Quite el "limitado" y puede hacer asignaciones con él, pero solo se pueden suministrar tipos que se pueden asignar. En el otro extremo, podrías definirlo como:type The_Transfer_Type is (<>) y luego podría suministrar cualquier entero o tipo enumerado, y ganaría cosas como 'first. Yendo más lejos, podrías hacer type The_Transfer_Type is range <>, y obtendrá la capacidad de realizar operaciones de matemáticas enteras, pero solo podría suministrar tipos numéricos enteros.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top