我一直在研究使用一些明智的静态断言来改进错误消息。这是一个例子:
#include <type_traits>
template<typename T> struct is_less_than_comparable {
template<typename Test> static char test(decltype(*static_cast<Test*>(nullptr) < *static_cast<Test*>(nullptr)));
template<typename Test> static int test(...);
static const bool value = std::is_same<char, decltype(test<T>(true))>::value;
};
template<typename K, typename V> class map {
public:
static_assert(is_less_than_comparable<K>::value, "Key type must be less-than comparable!");
};
struct x {};
int main() {
map<x, int> intmap;
}
IDEONE 会愉快地拒绝此代码,并给出我希望得到的漂亮、干净的错误消息(无论如何,一旦您将 nullptr 替换为 0)。但是 MSVC 不会触发静态断言并编译这段代码就好了——即使我添加了一些成员函数并开始调用它们也是如此。
最佳答案
问题在于 VC++ 2010 对元函数 is_less_than_comparable
的处理, 不适用于 static_assert
.
如果将代码更改为:
static const bool value = std::is_same<double, decltype(test<T>(true))>::value;
那么无论选择哪个重载,它都将为 false。然后触发断言。
显然选择了错误的重载,SFINAE 没有删除带有 char
的候选者返回类型。
更简单的测试(错误地打印 1
):
#include <type_traits>
template<typename T> struct is_less_than_comparable {
template<typename Test> static char test(decltype(*static_cast<Test*>(nullptr) < *static_cast<Test*>(nullptr)) b);
template<typename Test> static int test(...);
static const bool value = std::is_same<char, decltype(test<T>(true))>::value;
};
struct x {};
#include <iostream>
int main() {
std::cout << is_less_than_comparable<x>::value << std::endl;
}
编译器无缘无故地提供一个生成bool operator<(x, x)
运算符,从而int is_less_than_comparable<T>::test<T>(bool)
.如果提供了用户定义的比较运算符,则会正确选取其返回类型。该运算符不包含其中一个 header ,我可以重现 decltype
解析为 bool
不包含 header 。
这会产生正确的错误:
decltype(*(x*)nullptr < *(x*)nullptr) b;
error C2676: binary '<' : 'x' does not define this operator or a conversion to a type acceptable to the predefined operator
我认为这与 VC++ 不执行模板相关参数的两阶段查找有关。
关于c++ - 无法在 MSVC10 中使用 SFINAE、类型特征和 static_assert,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6300203/