web-dev-qa-db-ja.com

C ++で同等のAdaサブタイプ

C++は、型を絞り込むためにAdaのsubtypeに似たものを提供しますか?

例えば。:

type Weekday is (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);
subtype Working_Day is Weekday range Monday .. Friday;
16
sornbro

いいえ、ネイティブではありません。

あなたが説明することは、スコープ付き列挙型として最もよく表され、「親」スコープ付き列挙型と数値表現を共有する列挙型のサブセットを持つ別個のスコープ付き列挙型が付随します。

2つの間の変換をさらに定義することもできますが、リフレクションがなければ、すべてをエレガントで直感的にすることは実際には不可能です。少なくとも、目的をかなり損なうようなものをハードコーディングして複製する必要があります。

C++をプログラミングするときは、他の言語でのプログラミングに染み込んだ考え方を完全に放棄しようとするのが最善です。

そうは言っても、私は息を止めませんが、これは実際にはかなり素晴らしい機能のアイデアです!

回避策:列挙型を使用し、必要な場所に範囲チェックを適用します。

C++列挙とAda列挙の間にはいくつかの追加の違いがあります。次のAdaコードは、これらの違いのいくつかを示しています。

with Ada.Text_IO; use Ada.Text_IO;

procedure Subtype_Example is
   type Days is (Monday, Tueday, Wednesday, Thursday, Friday, Saturday, Sunday);
   subtype Work_Days is Days range Monday..Friday;

begin
   Put_Line("Days of the week:");
   for D in Days'Range loop
      Put_Line(D'Image);
   end loop;
   New_Line;
   Put_Line("Days with classification:");
   for D in Days'Range loop
      Put(D'Image & " is a member of");
      if D in Work_Days then
         Put_Line(" Work_Days");
      else
         Put_Line(" a non-work day");
      end if;
   end loop;

end Subtype_Example;

このプログラムの出力は次のとおりです。

Days of the week:
MONDAY
TUEDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
SUNDAY

Days with classification:
MONDAY is a member of Work_Days
TUEDAY is a member of Work_Days
WEDNESDAY is a member of Work_Days
THURSDAY is a member of Work_Days
FRIDAY is a member of Work_Days
SATURDAY is a member of a non-work day
SUNDAY is a member of a non-work day

サブタイプWork_Daysには、タイプDaysとの関係があります。 Work_Daysのすべてのメンバーは、Daysのメンバーでもあります。この例では、Work_Daysの有効な値のセットは、Daysの有効な値のセットのサブセットです。

Adaの文字は列挙型として定義されています。したがって、特別な用途のために文字型のサブタイプを定義するのは簡単です。次の例では、ファイルからテキストを読み取り、ファイル内の他のすべての文字を無視して、大文字と小文字の出現回数をカウントします。

with Ada.Text_IO; use Ada.Text_IO;

procedure Count_Letters is
   subtype Upper_Case is Character range 'A'..'Z';
   subtype Lower_Case is Character range 'a'..'z';

   Uppers : array(Upper_Case) of Natural;
   Lowers : array(Lower_Case) of Natural;

   File_Name : String(1..1024);
   File_Id   : File_Type;
   Length    : Natural;
   Line      : String(1..100);
begin
   -- set the count arrays to zero
   Uppers := (Others => 0);
   Lowers := (Others => 0);

   Put("Enter the name of the file to read: ");
   Get_Line(Item => File_Name,
            Last => Length);

   -- Open the named file
   Open(File => File_Id,
        Mode => In_File,
        Name => File_Name(1..Length));

   -- Read the file one line at a time
   while not End_Of_File(File_Id) loop
      Get_Line(File => File_Id,
               Item => Line,
               Last => Length);
      -- Count the letters in the line
      for I in 1..Length loop
         if Line(I) in Upper_Case then
            Uppers(Line(I)) := Uppers(Line(I)) + 1;
         elsif Line(I) in Lower_Case then
            Lowers(Line(I)) := Lowers(Line(I)) + 1;
         end if;
      end loop;
   end loop;
   Close(File_Id);

   -- Print the counts of upper case letters
   for Letter in Uppers'Range loop
      Put_Line(Letter'Image & " =>" & Natural'Image(Uppers(Letter)));
   end loop;

   -- print the counts of lower case letters
   for Letter in Lowers'Range loop
      Put_Line(Letter'Image & " =>" & Natural'Image(Lowers(Letter)));
   end loop;
end Count_Letters;

Characterの2つのサブタイプが定義されています。サブタイプUpper_Caseには、「A」から「Z」までの文字値の範囲が含まれ、サブタイプLower_Caseには、「a」から「z」までの文字値の範囲が含まれます。

読み取った文字を数えるために2つの配列が作成されます。配列Uppersは、Upper_Case値のセットによってインデックスが付けられます。配列の各要素はNaturalのインスタンスです。これは、負でない値のみを含むIntegerの事前定義されたサブタイプです。配列Lowersは、Lower_Case値のセットによってインデックスが付けられます。 Lowersの各要素もNaturalのインスタンスです。

プログラムはファイル名の入力を求め、そのファイルを開き、ファイルを一度に1行ずつ読み取ります。各行の文字が解析されます。文字がUpper_Case文字の場合、解析された文字でインデックス付けされたUppersの配列要素がインクリメントされます。文字がLower_Case文字の場合、解析された文字でインデックス付けされたLowersの配列要素がインクリメントされます。

次の出力は、count_lettersプログラムのソースファイルを読み取った結果です。

Enter the name of the file to read: count_letters.adb
'A' => 3
'B' => 0
'C' => 12
'D' => 0
'E' => 2
'F' => 13
'G' => 2
'H' => 0
'I' => 21
'J' => 0
'K' => 0
'L' => 36
'M' => 1
'N' => 9
'O' => 7
'P' => 4
'Q' => 0
'R' => 3
'S' => 2
'T' => 3
'U' => 9
'V' => 0
'W' => 0
'X' => 0
'Y' => 0
'Z' => 1
'a' => 51
'b' => 3
'c' => 8
'd' => 19
'e' => 146
'f' => 15
'g' => 16
'h' => 22
'i' => 50
'j' => 0
'k' => 0
'l' => 38
'm' => 13
'n' => 57
'o' => 48
'p' => 35
'q' => 0
'r' => 62
's' => 41
't' => 78
'u' => 19
'v' => 0
'w' => 12
'x' => 2
'y' => 6
'z' => 2
4
Jim Rogers

あなたが望むものは(少なくとも部分的に)C++ 17で導入された_std::variant_を使用して実現されるかもしれません。

_struct Monday {};
struct Tuesday {};
/* ... etc. */
using WeekDay= std::variant<Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday>;
_

次のコードは、送信されたタイプから新しいvariantを構築する_sub_variant_t_を定義します。例えば。 _using Working_Day= sub_variant_t<WeekDay,5>;_は、Weekdayから最初の5つの要素を取得します。

_template<class T,size_t o,class S>
struct sub_variant_h;

template<class T,size_t o,size_t... I>
struct sub_variant_h<T,o,std::index_sequence<I...> >
{
    using type= std::variant<typename std::variant_alternative_t<(I+o),T>... >;
};

template<class T,size_t end, size_t beg=0>
struct sub_variant
{
    using type= typename sub_variant_h<T,beg,std::make_index_sequence<end-beg> >:type;
};

template<class T,size_t end, size_t beg=0>
using sub_variant_t = typename sub_variant<T,end,beg>::type;
_

小さいタイプ(_Working_Day_)から大きいタイプ(WeekdayWeekDay d3= var2var<WeekDay>( d1 );を使用できます。ここで、_var2var_は次のように定義されます。

_template<class toT, class... Types>
toT
var2var( std::variant<Types...> const & v )
{
    return std::visit([](auto&& arg) -> toT {return toT(arg);}, v);
}
_

これを参照してください livedemo

4
Claas Bontus