Вызов функций с разным количеством аргументов в макросах Rust - PullRequest
0 голосов
/ 24 апреля 2018

Мне нужен макрос, который будет вызывать функции с различным числом аргументов, или макрос, который будет генерировать действительный список аргументов из его (повторяющихся) параметров.

Я согласен с явным предоставлением информации о числеаргументов к макросу, но я не могу понять, как создать список аргументов для функции - я всегда натыкаюсь на макросы, возвращающие выражения, а не на дерево токенов.

Я создал следующую площадкупример :

macro_rules! call (
    ($f: expr, $($params:tt)*) => {
        $f(make_params!($($params:tt)*))
    };
);

macro_rules! make_params {
    () => {};
    (I $($params: tt)*) => {
        1, make_params!($($params:tt)*)
    };
}


fn foo(a: i32, b: i32, c: i32) {
    println!("foo: {} {} {}", a, b, c);
}

fn bar(a: i32, b: i32) {
    println!("bar: {} {}", a, b);
}

fn main() {
    call!(foo, I I I);
    call!(bar, I I);
}

Компилятор жалуется на следующее:

error: macro expansion ignores token `,` and any following
  --> src/main.rs:10:10
   |
10 |         1, make_params!($($params:tt)*)
   |          ^
   |
note: caused by the macro expansion here; the usage of `make_params!` is likely invalid in expression context
  --> src/main.rs:3:12
   |
3  |         $f(make_params!($($params:tt)*))
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...

Как можно трактовать возврат make_params! как поток токенов (или такой), а невыражение?

Мой реальный пример использования немного сложнее, чем этот игрушечный пример.Мои функции имеют несколько типов параметров, которые создаются по-разному.В моем случае простое создание макросов call1, call2!, ... не кажется хорошим решением, так как мне понадобятся call_IIOOI, call_IIIO и т. Д.

1 Ответ

0 голосов
/ 25 апреля 2018

Вы должны строить вызов функции постепенно, по мере того, как вы идете, и в конце концов генерировать его только сразу:

macro_rules! call (
    ($f: expr, $($params:tt)*) => {
        make_call!($f, () $($params)*)
    };
);

macro_rules! make_call {
    ($f: expr, ($($args:tt)*)) => { $f($($args)*) };
    ($f: expr, () I $($params:tt)*) => {
        make_call!($f, (1) $($params)*)
    };
    ($f: expr, ($($args:tt)*) I $($params:tt)*) => {
        make_call!($f, ($($args)*, 1) $($params)*)
    };
}

площадка

...