是否可以使用元编程技巧在组装块上允许SFINAE?例如,检测处理器上是否提供像"CPUID"这样的指令:(这不是有效的代码,但说明了我想要实现的目标)
// This should work if `CPUID` is a valid instruction on the target architecture
template <
class... T,
class = decltype(sizeof...(T), asm volatile("CPUID":::)
>
bool f(T...) {
return true;
}
// This should fail because `BLAH` is not an instruction
template <
class... T,
class = decltype(sizeof...(T), asm volatile("BLAH":::)
>
bool f(T...) {
return true;
}
由于下面列出的多种原因,不可能以问题中表述的方式实现问题中制定的内容。但是,通过概括这个想法,它可能会成为有意义的东西,可以包含在语言的未来修订版中。
它不起作用的原因:
-
asm
块对C++编译器是不透明的。此类块的语法是特定于编译器的。我不认为MS VC++接受GCC和Intel编译器支持clobber列表的方式。此外,Microsoft的x86_64编译器停止支持汇编块,因为它们迫使人们使用内部函数。顺便说一下,也许依靠内部函数的存在可以用来提供编译时 CPU 调度?可能值得探索这个想法。 -
asm
块是特定于目标体系结构的。还有其他方法可以在编译时检测目标体系结构。 -
指令存在/不存在的概念非常模糊。哪个实体有权对任何给定的
asm
表达式做出决定:将其文本转换为机器代码的汇编程序还是运行实际代码的目标处理器本身?这两种选择都是有问题的。- 例如,"MOV"是许多架构的流行助记符名称。但是在所有情况下都是相同的指令吗?绑定到助记符的语义不太可能在不相关的体系结构之间匹配。
- 仅仅组装成功并不意味着它会很好地执行。例如,在英特尔 64 架构上,即使指令正确,指令也可能出错 #UD(未定义的指令信号),因为它的行为取决于由操作系统控制的 CR0 和 CR4 寄存器的运行时值。汇编程序在任何情况下都可以很好地处理它。必须运行代码。但是,如果我们进行交叉编译,并且由于目标处理器与主机处理器不匹配而无法运行它怎么办?
实际上,如果不先执行不透明块,就无法知道它的结果。因此,编译器可能希望调用任意程序来返回一个值,然后该值将用于模板扩展。然后,这样的程序可以进行处理器或指令感知,并返回其结果以进一步指导编译。
现在,这看起来足够抽象,可以成为一个语言功能,因为我们对这样一个外部程序的性质没有假设。仍然存在可移植性(+交叉编译)问题和安全性(运行外部程序有风险)问题。总而言之,对我来说,依赖从环境中进入编译器的现有宏定义看起来更好。