0

我一直在研究使用一些明智的静态断言来改进错误消息。这是一个例子:

#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 不会触发静态断言并很好地编译这段代码——即使我添加了一些成员函数并开始调用它们。

4

2 回答 2

1

我不确定您在这里的答案中要寻找什么,所以这里有一个在 VC++ 2010 中可以正常工作的类型特征:

#include <type_traits>

namespace supports
{
    namespace details
    {
        struct return_t { };

        template<typename T>
        static T& make();
    }

    template<typename T>
    details::return_t operator <(T const&, T const&);

    template<typename T>
    struct less_than : std::integral_constant<
        bool,
        !std::is_same<
            decltype(details::make<T>() < details::make<T>()),
            details::return_t
        >::value
    > { };
}
于 2011-06-10T02:14:42.723 回答
1

问题在于 VC++ 2010 处理元函数is_less_than_comparable,而不是static_assert.

如果您将代码更改为:

static const bool value = std::is_same<double, decltype(test<T>(true))>::value;

那么无论选择哪个重载,它都是错误的。然后断言触发。

显然选择了错误的重载,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). 如果提供了用户定义的比较运算符,则其返回类型被正确选取。该运算符没有包含其中一个标题,我可以在不包含标题的情况下decltype重新解析bool

这会产生正确的错误:

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++ 不执行模板相关参数的两阶段查找有关。

于 2011-06-09T23:09:45.263 回答