Могу ли я использовать шаблон переменной для объявления другого шаблона переменной?
Шаблоны переменных в C++14 (и Clang уже их поддерживают) и предложение стандарта is_same_v
и аналогично чертам типа, я подумал, что возможность создавать новые черты типа следующим образом:
template<typename T>
constexpr bool is_const_and_volatile{std::is_const_v<T> && std::is_volatile_v<T>};
Увы, это приводит к ошибкам, эквивалентным следующему SSCCE ( этот содержит все упомянутое ниже):
#include <type_traits>
template<typename T>
constexpr bool is_pointer{std::is_pointer<T>::value};
template<typename T>
constexpr bool foo{is_pointer<T>};
int main() {
//foo<int *>;
}
С линией в main
прокомментировал, Clang выплевывает следующее:
предупреждение: переменная
is_pointer<type-parameter-0-0>
имеет внутреннюю связь, но не определена
Это выглядит определенным для меня (обратите внимание, что изменение T
в int *
в foo
работает отлично). Раскомментируйте строку в main
создать экземпляр foo
дает это (опять же, T
в int *
работает отлично):
ошибка: переменная constexpr
foo<int *>
должен быть инициализирован константным выражением
Тем не менее, замена foo
со следующим старым синтаксисом заставляет оба экземпляра работать нормально:
constexpr bool foo{std::is_pointer<T>::value};
Что-то мне не хватает в шаблонах переменных? Можно ли с их помощью создавать новые шаблоны переменных или я вынужден использовать старый синтаксис для создания новых и пользоваться синтаксическим сахаром только при использовании их для другого кода?
2 ответа
Ваш код действителен и принят clang SVN. Ошибка ссылки была вызвана ошибкой clang 17846, которую я исправил пару дней назад.
Кажется, работает следующее:
#include <type_traits>
#include <iostream>
template<typename T>
struct test {
static constexpr bool is_pointer{std::is_pointer<T>::value};
};
template<typename T>
constexpr bool test<T>::is_pointer;
template<typename T>
constexpr bool foo{test<T>::is_pointer};
int main() {
std::cout << foo<bool>;
std::cout << foo<bool*>;
}
Хотя это вызывает то же самое предупреждение, если используется в constexpr
контекст, так что я полагаю, что на самом деле это не работает.
// Fail
template<typename T>
typename std::enable_if<foo<T>, void>::type bar()
{
}
int main() {
bar<bool*>();
}
main.cpp:21:5: error: no matching function for call to 'bar'
bar<bool*>();
^~~~~~~~~~
main.cpp:16:45: note: candidate template ignored: substitution failure [with T = bool *]: non-type template argument is not a constant expression
typename std::enable_if<foo<T>, void>::type bar()
Это перестает жаловаться, если вы даете foo
явный тип:
template<typename T>
typename std::enable_if<foo<bool*>, void>::type bar()
{
}
Или просто использовать test<T>::is_pointer
непосредственно:
template<typename T>
typename std::enable_if<test<T>::is_pointer, void>::type bar()
{
}