Рассмотрим этот код:
#include <tuple>
#include <type_traits>
#include <iostream>
template <typename T, typename = void> struct is_tuple_like : std::false_type {};
template <typename T> struct is_tuple_like<T, decltype(std::tuple_size_v<T>, void())> : std::true_type {};
int main()
{
std::cout << is_tuple_like<std::string>::value << '\n';
}
Выполнить на gcc.godbolt.org KBD>
В GCC 10.2 и MSVC 19.28 это вызывает серьезную ошибку, например:
error: incomplete type 'std::tuple_size<...>' used in nested name specifier
С другой стороны, в Clang 11.0.1 он компилирует и печатает 1
как с libstdc ++, так и с libc ++.
Какой компилятор здесь правильный?
Обратите внимание, что Clang печатает 1
, а не 0
, что означает, что он не рассматривает std::tuple_size<std::string>::value
(инициализатор tuple_size_v
) как программную ошибку, а вместо этого предпочитает полностью игнорировать ее!
В каком-то смысле это имеет смысл, поскольку если tuple_size_v
определяется как template <typename T> inline constexpr size_t tuple_size_v = ...
, тип decltype(tuple_size_v<...>)
не зависит от параметра шаблона и всегда равен size_t
.
Я предполагаю, что вопрос сводится к тому, требуется ли здесь создавать экземпляр инициализатора tuple_size_v
, хотя это и не является строго необходимым.
Я знаю, что могу исправить это, заменив std::tuple_size_v<...>
на std::tuple_size<...>::value
, тогда он напечатает 0
во всех трех компиляторах.
size_t
или не кsize_t
можно сделать более явным. - person StoryTeller - Unslander Monica   schedule 15.02.2021void
, Clang выведет 0. Это странно. - person xskxzr   schedule 16.02.2021decltype(...)
теперь неvoid
, поэтому специализация не совпадает и выбран первичный шаблон. - person HolyBlackCat   schedule 16.02.2021std::size_t
. - person xskxzr   schedule 17.02.2021