Не могу использовать SFINAE, набрать traits и static_assert в MSVC10 - PullRequest
0 голосов
/ 10 июня 2011

Я исследовал использование некоторых разумных статических утверждений для улучшения сообщений об ошибках.Вот пример:

#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 не будет запускать статическое утверждение и просто скомпилирует этот код, даже если я добавлю некоторые функции-члены и начну вызывать их.

Ответы [ 2 ]

1 голос
/ 10 июня 2011

Я не уверен, что вы ищете в ответе здесь, поэтому вот черта типа, которая отлично работает в 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
    > { };
}
1 голос
/ 10 июня 2011

Проблема в том, что 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 ++ не выполняет двухфазный поиск аргументов, зависящих от шаблона.

...