エニュメレーションを一貫して行うにはどうしたらいいですか? - ページ 7

 
Комбинатор:

コメントにあるような普通の名前はどうなんだろう?

Dynamic ENUMは内部用で、設定画面には表示されません。通常の名前/コメントはあまり必要ない
 

ところで、mqlプリプロセッサーにエラーがあるようです。

#define  i ##nt  ll;

が 'i nt ll;' と展開され、エラーとなる。

'i nt' - undeclared identifier    t_t_t.mq4    50    1


列挙のコメントについてですが、理論的にはCプリプロセッサにツッコミを入れるはずです。だから、仮にコメントを詰め込むことができたとしても、その効果は期待できないだろう。良い意味で、構文を変え(例えば_cmnt_に)、コメントを引っ張ってくるプリプロセッサでCプリプロセッサの呼び出し順序を変えるべきでしょう。そのような改革が行われる見込みは低いと思います ))

 
pavlick_:

ところで、mqlプリプロセッサーにエラーがあるようです。

が 'i nt ll;' と展開され、エラーとなる。

どこかにエラーがあります。正しく展開すると、'nt ll'となります。
 
Alexander Puzanov:
Dynamic ENUMは内部用で、設定画面には表示されません。通常の名前/コメントはあまり必要ない
このような動的なenumは、もっときれいな形に押し込めることができる。
 

最後の方法は、enumと値の配列を返す関数について、空白を手書きする必要がありました。それを解明して、不要になったものを書くことにしたのです。ただし、mqlでコンパイルできない、引数の数が可変のマクロはないが、理論的には出現する可能性がある。とにかく、こんな感じです。

// Выглядит страшно, да )). Но это универсальная заготовка
// Можно засунуть в какой-нибудь cpp_magic.h
//cpp_magic.h
#define  EVAL(...) EVAL1024(__VA_ARGS__)
#define  EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
#define  EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
#define  EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
#define  EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
#define  EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
#define  EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define  EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define  EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define  EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define  EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define  EVAL1(...) __VA_ARGS__
#define  SECOND(a, b, ...) b
#define  FIRST(a, ...) a
#define  CAT(a,b) a ##  b
#define EMPTY()
#define  DEFER1(m) m EMPTY()
#define  DEFER2(m) m EMPTY EMPTY()()
#define  DEFER3(m) m EMPTY EMPTY EMPTY()()()
#define  DEFER4(m) m EMPTY EMPTY EMPTY EMPTY()()()()
#define  IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define  PROBE() ~, 1
#define  NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()
#define  BOOL(x) NOT(NOT(x))
#define  HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0
#define  IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)
#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...)             _IF_0_ELSE
#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__
#define  MAP1(m, first, ...)          \
  m(first)                           \
  IF_ELSE(HAS_ARGS(__VA_ARGS__))(    \
  DEFER2(_MAP1)()(m, __VA_ARGS__)    \
  )()
#define _MAP1() MAP1
#define  MAP2(m, first, second, ...)  \
  m(first, second)                   \
  IF_ELSE(HAS_ARGS(__VA_ARGS__))(    \
  DEFER2(_MAP2)()(m, __VA_ARGS__)    \
  )()
#define _MAP2() MAP2
// main.cpp
#include <stdio.h>
#include "cpp_magic.h"

#define  CREATE_ENUM_HELPER_1(el, val)  el = val,
#define  CREATE_ENUM_HELPER_2(el, val)  el,
#define  CREATE_ENUM(name, ...)                                     \
  enum name{                                                       \
    EVAL( MAP2(CREATE_ENUM_HELPER_1, __VA_ARGS__) )                \
  };                                                               \
  unsigned get_##name##_array(int *ar){                            \
    int temp[] = {                                                 \
    EVAL( MAP2(CREATE_ENUM_HELPER_2, __VA_ARGS__) )                \
    };                                                             \
    if(ar != NULL)                                                 \
      for(unsigned i = 0;  i < sizeof(temp) / sizeof(int);  ++i){  \
        ar[i] = temp[i];                                           \
    }                                                              \
    return sizeof(temp) / sizeof(int);                             \
  };

CREATE_ENUM(enum1, q,1, e,3, t,65, z,90)
CREATE_ENUM(enum2, ww,100, ss,-3, dh,21)
struct S{
  CREATE_ENUM(enum3, q,871, e,213, t,226)
}s;

int main()
{
  int ar[100];

  printf("----enum1-----\n");
  get_enum1_array(ar);
  for(unsigned i = 0;  i < get_enum1_array(NULL);  ++ i)
    printf("%d\n", ar[i]);

  printf("----enum2-----\n");
  get_enum2_array(ar);
  for(unsigned i = 0;  i < get_enum2_array(NULL);  ++ i)
    printf("%d\n", ar[i]);

  printf("----enum3-----\n");
  s.get_enum3_array(ar);
  for(unsigned i = 0;  i < s.get_enum3_array(NULL);  ++ i)
    printf("%d\n", ar[i]);
}

Выхлоп printf:
 ----enum1-----
 1
 3
 65
 90
 ----enum2-----
 100
 -3
 21
 ----enum3-----
 871
 213

226

// emum1 の生成コード
// enum enum1{
// q = 1,
// e = 3,
// t = 65,
// z = 90,
// };
、 // unsigned get_enum1_array(int *ar){
// int temp[] = { q, e, t, z, };
// if(ar != NULL)
// for(unsigned i = 0; i < sizeof(temp) / sizeof(int); ++i){
// ar[i] = temp[i]; }
// return sizeof(temp) / sizeof(int);
// } }.

このテーマに関する記事http://jhnet.co.uk/articles/cpp_magic. もちろん、たくさんの魔法を駆使して。しかし、この技術はプリプロセッサのコード生成に言及する幅広いタスクに有効である。

C Pre-Processor Magic - Articles - Jhnet
  • jhnet.co.uk
The C Pre-Processor (CPP) is the somewhat basic macro system used by the C programming language to implement features such as and which allow very simple text-substitutions to be carried out at compile time. In this article we abuse the humble to implement if-statements and iteration. Before we begin, a disclaimer: these tricks, while perfectly...
 
悔しいけど)でも、クドい。
 

スレッドを興味深く読ませていただきました、どれもマクロでとてもかっこいいですね。

なぜenumでこんなにも踊る必要があるのか、はっきりしないのです。具体的な例を教えてください。

TFについてはクリアしていますが、他には?

 
pavlick_:

しかし、mqlではコンパイルできないし、引数の数が可変のマクロはないが、理論的には出現しうる。

MQL5では、マクロは引数の数が決まっているだけでなく、その数は8個に制限されているので、3つの値しかないenumを作ることができます。

理論的な外観については、開発者がすでに何かを約束したように、enumのパースのためのインハウス関数を取得する方が早いでしょう。

 
Alexey Navoykov:

MQL5では、マクロは引数の数が決まっているだけでなく、その数は8個に制限されているので、3つの値だけを対象としたenumを作ることができます。

理論的な見栄えとしては、enumのパース用の関数を社内で用意した方が早いかもしれません。 開発者はすでに何かを考え出すと約束しています。

enum 値を列挙するためのイテレータは予定していない。
先に提案した、配列を用いた列挙方法を用いる。
enum Enum
 {
  VAL_0,
  VAL_1,
  ...
 };

const  Enum EnumValues[]={ VAL_0, VAL_1, ... };

for(uint i=0;i<ArraySize(EnumValues);i++)
   Print(EnumToString(EnumValues[i]));
 
Ilyas:
列挙型値列挙のためのイテレータは予定していない。
先に提案した、配列を使って値を列挙する方法を使います。
同じスイッチでも、横から見るとそうなっていることがわかります。つまり、どのような場合でも、列挙者自身と配列(スイッチケース)の2つのリストを維持する必要がある。