Могу ли я использовать шаблон переменной для объявления другого шаблона переменной?

Шаблоны переменных в 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()
{
}
Другие вопросы по тегам