我对SFINAE很陌生,想知道如果多个std::enable_if_t<true, std::is_...<T>>
最终应用于T
,编译器是否会选择哪个模板。
如本例所示:
template<typename T, typename = void>
class Thing {
// Thing A
};
template<typename T>
class Thing<T, std::enable_if_t<true, std::is_scalar<T>> {
// Thing B
};
template<typename T>
class Thing<T, std::enable_if_t<true, std::is_float<T>> {
// Thing C
};
template<typename T>
class Thing<T, std::enable_if_t<true, std::is_signed<T>> {
// Thing D
};
template<>
class Thing<float> {
// Thing E
};
int main(){
Thing<float> x; // what order would the compiler try out?
}
我认为它会尽量选择";特定的";模板专业化,所以E
在前,A
在后,但这就是我所确信的。我不知道它将如何从B
、C
或D
中消除歧义,也不知道如果我需要控制消除歧义的过程,如何组合T
的多个条件。
还要回答一个问题:不,这种优先级不存在。enable_if的操作虽然聪明,但要么失败,要么成功。更重要的是,替换发生在任何潜在的实例化相互比较之前。这种比较的规则很复杂,但在您的示例中,它确实可以归结为选择最专业的选项,使用以下排名:
- 事物A是主要的(最不专业的(模板
- 事物B、C和D同样专业,但比A更专业
- E是最专业的
因此将选择E。B、 必须考虑C和D,因为它们的条件都被评估为true
,并且它们同样专门化,因为它们每个都有单个类型参数T
。由于一个有效的程序每次使用一个名称都必须有一个明确的匹配,因此如果从示例中删除Thing E,就会出现编译器错误。
现在,可以通过使用具有更合适(组合(条件的enable_if来消除B、C和D的歧义,并且歧义问题不会通过使用概念而神奇地消失。然而,您可以直接将概念与模板参数一起使用,例如:
#include <concepts>
template<typename T>
class Thing {}; // Thing A
template<std::integral T>
class Thing<T> {}; // Thing B
template<std::signed_integral T>
class Thing<T> {}; // Thing C
template<std::floating_point T>
class Thing<T> {}; // Thing D
template<>
class Thing<float> {}; // Thing E
int main() {
Thing<float> E;
Thing<double> D;
Thing<int> C;
Thing<bool> B;
Thing<void> A;
}
这只是一个简短的例子,但我认为概念是对通用C++的重大改进,应该把它们作为模板来教授和学习。它们现在得到了广泛的支持,所以如果您碰巧有一个较旧的编译器,您可以随时在编译器资源管理器上试用它们。