英文:
Generalizing `macro_rules!` matches
问题
我有一个宏,根据提供的参数以稍微不同的方式调用另一个宏。
macro_rules! do_things {
	($($e:expr),*) => { ... }
}
macro_rules! do_more_things {
	($($e:expr),* ; $val1:expr, $cond:expr) => {
		{
			do_things!($($e),*);
			if $cond {
				do_things!(MAGIC_CONST_1 | $val1);
				call_something($cond);
			} else {
				do_things!(MAGIC_CONST_2 | $val1, $cond);
			}
		}
	};
	($($e:expr),* ; $val1:expr, $val2:expr, $cond:expr) => {
		{
			do_things!($($e),*);
			if $cond {
				do_things!(MAGIC_CONST_1 | $val1, $val2);
				call_something($cond);
			} else {
				do_things!(MAGIC_CONST_2 | $val1, $val2, $cond);
			}
		}
	};
}
如何泛化以消除两个非常相似的分支?如果有帮助的话,此处的 do_things!(a, b); 相当于 do_things!(a); do_things!(b)。
英文:
I have a macro that calls another macro in a slightly different way based on the arguments provided.
macro_rules! do_things {
	($($e:expr),*) => { ... }
}
macro_rules! do_more_things {
	($($e:expr),* ; $val1:expr, $cond:expr) => {
		{
			do_things!($($e),*);
			if $cond {
				do_things!(MAGIC_CONST_1 | $val1);
				call_something($cond);
			} else {
				do_things!(MAGIC_CONST_2 | $val1, $cond);
			}
		}
	};
	($($e:expr),* ; $val1:expr, $val2:expr, $cond:expr) => {
		{
			do_things!($($e),*);
			if $cond {
				do_things!(MAGIC_CONST_1 | $val1, $val2);
				call_something($cond);
			} else {
				do_things!(MAGIC_CONST_2 | $val1, $val2, $cond);
			}
		}
	};
}
How can I generalize it to eliminate two very similar branches?
If it helps, do_things!(a, b); in this case is equivalent to do_things!(a); do_things!(b).
答案1
得分: 1
不可能完全按照这种调用方式实现,但你可以重新排列参数,使条件在所有值之前出现:
macro_rules! do_more_things {
    ($cond:expr, $($e:expr),* ; $val1:expr $(, $val2:expr)? ) => {
        {
            do_things!($($e),*);
            if $cond {
                do_things!(MAGIC_CONST_1 | $val1 $(, $val2)?);
                call_something($cond);
            } else {
                do_things!(MAGIC_CONST_2 | $val1 $(, $val2)?, $cond);
            }
        }
    };
}
或者,你可以像 @BallpointBen 建议的那样,更改条件和值之间的分隔符为某个明显的内容。
英文:
It's not possible with exactly that invocation, but you can either rearrange the arguments so that the condition comes before all the values:
macro_rules! do_more_things {
    ($($e:expr),* ; $cond:expr, $val1:expr $(, $val2:expr)? ) => {
        {
            do_things!($($e),*);
            if $cond {
                do_things!(MAGIC_CONST_1 | $val1 $(, $val2)?);
                call_something($cond);
            } else {
                do_things!(MAGIC_CONST_2 | $val1 $(, $val2)?, $cond);
            }
        }
    };
}
alternatively you can change the separator between the condition and the values to something distinct like @BallpointBen suggests
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论