#c #visual-studio-2010 #c 11 #visual-c #static-assert
#c #visual-studio-2010 #c 11 #visual-c #статическое утверждение
Вопрос:
Я исследовал использование некоторых разумных статических утверждений для улучшения сообщений об ошибках. Вот пример:
#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 не запускает статическое утверждение и отлично компилирует этот код — даже если я добавлю некоторые функции-члены и начну вызывать их.
Комментарии:
1. Код компилируется не для меня. Нужны ли какие-то дополнительные заголовочные файлы?
2. Я думаю, это связано с тем, что VC не выполняет двухфазный поиск аргументов, зависящих от шаблона.
3. @BenVoigt : У меня сложилось впечатление, что VC 2010 просто напросто ломается при попытке использовать
decltype
для SFINAE. Я вообще отказался от попыток его использовать: -[4. Вы должны проверить недавно добавленные свойства оператора для повышения. Признаки типа
Ответ №1:
Проблема заключается в обработке метафункции в 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)
. Если предоставляется определяемый пользователем оператор сравнения, его возвращаемый тип выбран правильно. Этот оператор не входит ни в один из заголовков, я могу воспроизвести 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 не выполняет двухфазный поиск аргументов, зависящих от шаблона.
Ответ №2:
Я не уверен, что вы ищете в ответе здесь, поэтому вот type trait, который отлично работает в VC 2010:
#include <type_traits>
namespace supports
{
namespace details
{
struct return_t { };
template<typename T>
static Tamp; make();
}
template<typename T>
details::return_t operator <(T constamp;, T constamp;);
template<typename T>
struct less_than : std::integral_constant<
bool,
!std::is_same<
decltype(details::make<T>() < details::make<T>()),
details::return_t
>::value
> { };
}