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

С появлением шаблонов переменных в 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};

Есть ли что-то, что мне не хватает в шаблонах переменных? Есть ли способ создавать новые шаблоны переменных с с их помощью, или я вынужден использовать старый синтаксис для создания новых и наслаждаться синтаксическим сахаром только при использовании их для другого кода?


person chris    schedule 26.01.2014    source источник
comment
Вы пробовали явное создание экземпляров? Люк Дантон недавно обнаружил ошибку, связанную с неявным созданием экземпляров..   -  person dyp    schedule 26.01.2014
comment
(Кажется, работает с явным созданием экземпляров: coliru.stacked-crooked.com/a/e16d249679a71d0c)   -  person dyp    schedule 26.01.2014
comment
@dyp, хорошо, но добавление одного для bool * в вашем примере все равно выдает ошибку компоновщика , к сожалению, не говоря уже о том, что я не могу явно создать экземпляр для каждого типа.   -  person chris    schedule 26.01.2014
comment
Я прочитал isocpp.org/files/papers/N3651.pdf. И я думаю, что это должно работать. Мне кажется, это лязг жука.   -  person user534498    schedule 26.01.2014
comment
@chris В вашем примере я вижу только предупреждения. Также ясно, что добавление явных экземпляров не помогает подавить общее предупреждение о том, что первичный шаблон is_pointer не определен. И, конечно же, это предназначено только для того, чтобы показать, что существует связь с неявным созданием экземпляров, а не как решение.   -  person dyp    schedule 26.01.2014
comment
@dyp, извините, я имел в виду предупреждение. Я думаю, что формулировка предупреждения заставляет меня неоднократно думать, что это ошибка компоновщика.   -  person chris    schedule 26.01.2014


Ответы (2)


Ваш код действителен и принят clang SVN. Ошибка ссылки была вызвана ошибкой clang 17846, которую я исправлено пару дней назад.

person Richard Smith    schedule 05.02.2014

Кажется, работает следующее:

#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()
{
}
person Community    schedule 26.01.2014