2017-02-11 9 views
1

マクロに引数を展開する場合、マクロ内に引数番号を含める方法がありますかマクロ展開で引数番号を使用していますか?

これは、特性を使用して構造体にインデックスを割り当てる方法を示す完全な例です。現在struct_number()は常に0を返します。これはマクロへの引数の順番に基づいて定数を返すことができますか?

struct Foo {_var: bool} 
struct Bar {_var: u8} 
struct Baz {_var: i16} 

trait NumberStruct { 
    fn struct_number() -> usize; 
} 

macro_rules! number_structs_impl { 
    ($($t:ty)*) => ($(
     impl NumberStruct for $t { 
      fn struct_number() -> usize { 
       // How to return a number based on the argument order? 
       return 0; 
      } 
     } 
    )*) 
} 

number_structs_impl!(Foo Bar Baz); 

fn main() { 
    // see if the numbers are correct 
    macro_rules! print_numbers { 
     ($($t:tt)*) => ($(
      print!("{}:{} ", stringify!($t), $t::struct_number()); 
     )*) 
    } 

    // should print: 
    // Baz:2 Bar:1 Foo:0 
    print_numbers!(Baz Bar Foo); 
    println!(); 
} 

答えて

0

これは行うことができます。

  • 最初にすべての引数を数えます。
  • 再帰マクロを使用すると、tail*引数を数えることができます。
  • オプションで構造体のリストをマクロに格納して、両方のマクロ呼び出しがリストを繰り返す必要がないようにします。

の作業例:

struct Foo {_var: bool} 
struct Bar {_var: u8} 
struct Baz {_var: i16} 

trait NumberStruct { 
    fn struct_number() -> usize; 
} 

macro_rules! count_tts { 
    () => {0usize}; 
    ($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)}; 
} 

macro_rules! number_structs_impl { 
    () => {}; 
    ($head:tt $($tail:tt)*) => { 
     impl NumberStruct for $head { 
      fn struct_number() -> usize { 
       return STRUCT_NUM - (1 + count_tts!($($tail)*)); 
      } 
     } 
     number_structs_impl!($($tail)*); 
    }; 
} 

// avoid repeating same structs 
macro_rules! apply_structs { 
    ($macro_id:ident) => (
     $macro_id! { 
      Foo 
      Bar 
      Baz 
     } 
    ) 
} 

const STRUCT_NUM: usize = apply_structs!(count_tts); 
apply_structs!(number_structs_impl); 

fn main() { 
    // see if the numbers are correct 
    macro_rules! print_numbers { 
     ($($t:tt)*) => ($(
      print!("{}:{} ", stringify!($t), $t::struct_number()); 
     )*) 
    } 

    // should print: 
    // Baz:2 Bar:1 Foo:0 
    print_numbers!(Baz Bar Foo); 
    println!(); 
} 

注:私はそれがマクロと2にマクロを渡す伴うためしかし、それは厄介なソリューションのビットは、その可能性を表示するには、この答えを投稿しています再帰マクロを展開できる場合は、の最後の引数を各再帰引数see related questionとすると、これをよりきれいに行うことができます。

0

番号付きの実装を定義する方法は、再帰マクロを使用することです。一意の番号はcounting argumentsによって作成できます。この場合、末尾の引数がカウントされます。

この問題は、最初の構造体の番号が最も大きく、最後の構造体のゼロがある場合はインデックスが逆になっています。

数値が一意である必要がある場合は問題ありませんが、この場合、各構造体インデックスはマクロに渡される順序と一致する必要があります。

入力引数は、再帰マクロsee this exampleを使用して元に戻すことができます。

apply_args_reverse!(macro_name, arg1 arg2 arg3) 

に展開さ::一般的なマクロを書くために、その可能性を、このマクロを使用する

もちろん

macro_name!(arg3 arg2 arg1) 

は、独自に非常に有用ではないthatsの、それがあれば便利です引数は直接記述されるのではなく、引数として渡されます。

これは、次のように各引数の数に展開されるマクロを作る作成するために使用することができます。

struct Foo {_var: bool} 
struct Bar {_var: u8} 
struct Baz {_var: i16} 

trait NumberStruct { 
    fn struct_number() -> usize; 
} 

macro_rules! count_args_space { 
    () => {0_usize}; 
    ($_head:tt $($tail:tt)*) => {1_usize + count_args_space!($($tail)*)}; 
} 

macro_rules! number_structs_impl { 
    (@single $t:tt $($tail:tt)*) => (
     impl NumberStruct for $t { 
      fn struct_number() -> usize { 
       return count_args_space!($($tail)*); 
      } 
     } 
    ); 

    () => {}; 
    ($head:tt $($tail:tt)*) => { 
     number_structs_impl!(@single $head $($tail)*); 
     number_structs_impl!($($tail)*); 
    }; 
} 

macro_rules! apply_args_reverse { 
    ($macro_id:tt [] $($reversed:tt)*) => { 
     $macro_id!($($reversed) *); 
    }; 
    ($macro_id:tt [$first:tt $($rest:tt)*] $($reversed:tt)*) => { 
     apply_args_reverse!($macro_id [$($rest)*] $first $($reversed)*); 
    }; 
    // Entry point, use brackets to recursively reverse above. 
    ($macro_id:tt, $($t:tt)*) => { 
     apply_args_reverse!($macro_id [ $($t)* ]); 
    }; 
} 

// Note that both commands below work, and can be swapped to reverse argument order. 

// number_structs_impl!(Foo Bar Baz); 
apply_args_reverse!(number_structs_impl, Foo Bar Baz); 

fn main() { 
    // see if the numbers are correct 
    macro_rules! print_numbers { 
     ($($t:tt)*) => ($(
      print!("{}:{} ", stringify!($t), $t::struct_number()); 
     )*) 
    } 

    print_numbers!(Baz Bar Foo); 
    println!(); 
} 

お知らせ文を:

number_structs_impl!(Foo Bar Baz); 

...と

apply_args_reverse!(number_structs_impl, Foo Bar Baz); 

...それぞれの構造体に割り当てられた番号の順序を逆にして、コメントを入れ替えることができます。


注:これは、より簡潔である一方で、マクロ展開が深くを入れ子に取得しているので、それは、ハード・ツー・トラブルシューティングの問題になりやすい、また、より多くの脆弱な私other answerを保ちます(私はこの中には、それがで動作するようになりました少なくとも)

関連する問題