在宏扩展中使用参数编号? [英] Using argument number in macro expansion?

查看:99
本文介绍了在宏扩展中使用参数编号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将参数扩展到宏时,是否可以在宏中包含参数编号

When expanding arguments to a macro, is there a way to include the argument number within the macro

这里是一个完整的示例,显示了如何使用它来使用特征将索引分配给结构.当前struct_number()始终返回0,是否可以根据宏参数的顺序将其返回为常数?

Here is a complete example showing how this might be used to assign an index to a struct using a trait. Currently struct_number() always returns 0, could this be made to return a constant number based on the order of the argument to the macro?

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!();
}

推荐答案

定义编号实现的一种方法是使用递归宏.可以通过计算参数(在这种情况下计算尾随参数)来创建唯一编号.

An approach to defining numbered implementations is to use a recursive macro. A unique number can be created by counting arguments, in this case counting trailing arguments.

与此有关的问题是,在第一个结构具有最大数量,最后一个结构为零的地方,索引被颠倒了.

The problem with this, is the indices are reversed where the first struct has the largest number, the last struct zero.

如果只需要数字是唯一的,那就没关系了,但是在这种情况下,我希望每个结构索引都与其传递给宏的顺序相匹配.

If you only need the numbers to be unique, it wont matter, however in this case I want each structs index to match the order its passed to the macro.

输入参数可以使用递归宏进行反转,请参见此示例.

Input arguments can be reversed using a recursive macro, see this example.

使用此宏,可以编写一个通用宏:

Using this macro, its possible to write a generic macro:

apply_args_reverse!(macro_name, arg1 arg2 arg3)

其中扩展为:

macro_name!(arg3 arg2 arg1)

当然这本身并不是很有用,但是如果参数不是直接写的而是作为参数传递的,则很有用.

Of course thats not very useful on its own, but it can be useful if the arguments aren't written directly, but passed as arguments.

这可用于创建使每个参数的编号扩展的宏,如下所示:

This can be used to create make a macro that expands with the number of each argument as follows:

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);

...是可互换的,带有注释的交换会颠倒分配给每个结构的数字顺序.

... are interchangeable, swapping which is commented reverses the order of numbers assigned to each struct.

注意:保留我的其他答案,虽然这更简洁,但它也更脆弱,容易难以理解-对问题进行故障排除,因为宏扩展深入嵌套(我在至少使其正常工作的同时发现了此问题).

Note: keeping my other answer, while this is more concise, it's also more fragile, prone to hard-to-troubleshoot problems, since macro expansion gets deeply nested (I found this while getting it to work at least).

这篇关于在宏扩展中使用参数编号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆