Вопрос по templates, c++, c++11 – Каков синтаксис выражения для поддержки типов C ++?

16

Я работал с шаблонным классом, который принимает набор целых чисел. Код был как,

template
struct work{ ... };

Затем я понял, что пользователю может потребоваться предоставить либо набор целых чисел, либо диапазон целых чисел. Итак, я немного изменил синтаксис для поддержки создания экземпляров, как,

work //instead of work
work //same as work 

В то время как в C ++ мы имеем большое количество операторов, и их можно использовать для формулирования экзотических шаблонов выражений (скажем,boost::xpressiveboost::lambdaboost::spirit и т. д.) возможностей для манипулирования типами гораздо меньше.

В выступлении Boostcon Шон Родитель отметил, что до сих пор не может написатьpair обозначатьa pair of integers, В моей персидской библиотеке я сделал такой синтаксисtuple обозначить кортеж из 3 целых чисел вместо записи кортежа с 3 int в аргументах типа, отмечая, что я нигде не записываю необработанный массив в качестве аргумента кортежа! (нота:std::array отличается от описанного выше, так как std :: array не может хранить ссылки, покаtuple можно сказатьstd::tuple возможно)

Итак, я хочу знать, что это за "выражения типа " Я могу написать?

До сих пор я могу думать о типе объекта, типе функции, ссылочном типе, с / без модификаторов cv, указателей и т. Д., Например

    template
    struct tpl;

    using t1 = tpl;//simple type
    //function (can have function pointer/reference also) 
    // e.g. void(*)(int,float) or void(&)(int,float)
    using t2 = tpl;
    //array can have pointer / reference also
    //e.g. int(&)[4] or int (*)[4]
    using t3 = tpl;
    using t4 = tpl;
    using t5 = tpl;//with cv modifiers
    using t6 = tpl;//with pointer
    using t7 = tpl;//with reference (& or &&)
    using t8 = tpl; //template itself
    using t9 = tpl; //variadic functions
    using t10 = tpl; //pointer to member

Но я верю, что возможно гораздо больше.

ПРИМЕЧАНИЕ: этот вопрос чисто теоретический,Я просто хочу знать все виды синтаксиса, которые я могу написать внутри <> в качестве аргумента типаи не о читабельности / морали, или даже о том, как я могу реализовать некоторые из приведенных мной примеров, например, рабочий класс.

Не уверен, почему это имеет 4 близких голосов. Там'Явная часть в стандарте, которая охватывает именно этот вопрос, что означает, что WG21 рассмотрела вопрос, который стоит рассмотреть. MSalters
@EJP Многие бесконечные вещи могут быть выражены в конечной форме. Paul Manta
@EJP Try "Любой типT с одним или несколькими слоями косвенного указателя, например, "I"char*, char**, char***, ...Я бы сказал, что предложение конечно. :) Timothy Shields
@abir, простите за недоразумение. Возможно, образец мог быть опущен / помещен в конце. Также, "Сколько *** мы можем иметь " вероятно, не совсем подходит для SO вопроса sehe

Ваш Ответ

2   ответа
6

о чем вы спрашиваете. Я думал, что образец, который вы дали, был интересным, и немного поиграл с ним.

Я придумал реализацию, которая делаетspan бытьпсевдоним шаблона заindexes, используя трюк типа вывода вconstexpr функции:

template <int a,="" int="" b=""> using span = decltype(expand_span<a,b>());
</a,b></int>

Теперь вы можете съесть свой торт и съесть его:

////////////////////////////////////////////////////////////////
// using indirect template arguments
template<typename> struct indirect_work { };

void test_indirect()
{
    indirect_work<indexes<1,2,3,4>> x;
    indirect_work<span<1,4>>        y;

    x = y; // x and y are of identical types
    static_assert(std::is_same<indexes<1,2,3,4>, span<1,4>>::value, "fact check");
}
</indexes<1,2,3,4></span<1,4></indexes<1,2,3,4></typename>

Но, возможно, более интересно,вы все еще можете иметь свой основнойwork шаблон сырой список аргументов шаблона:

////////////////////////////////////////////////////////////////
// using direct template arguments
template<int...> struct direct_work { };

// deduction alias:
template<int... direct=""> constexpr direct_work<direct...> deduction_helper(indexes<direct...>);
template <typename idx=""> using deduce = decltype(deduction_helper(Idx{}));

void test_direct()
{
    direct_work<1,2,3,4> x;
    deduce<indexes<1,2,3,4>> y;
    deduce<span<1,4>> z;

    static_assert(std::is_same<decltype(x), decltype(y)="">::value, "fact check");
    static_assert(std::is_same<decltype(x), decltype(z)="">::value, "fact check");
}
</decltype(x),></decltype(x),></span<1,4></indexes<1,2,3,4></typename></direct...></direct...></int...></int...>

Смотрите полную рабочую демонстрацию здесь:GCC на Ideone, Я скомпилировал это с Clang локально.

Полный код

Код дляexpand_span здесь дублируется на случай, если ссылка не работает:

#include <type_traits>

template <int...> struct indexes {};

namespace {
    template<int a,="" int...="" other="">
        constexpr indexes<a, other...=""> combine(indexes<other...> deduce);

    template<int a,="" int="" b,="" typename="" enable="void"> struct expand_span_; // primary

    template<int a,="" int="" b="">
    struct expand_span_<a, b,="" typename="" std::enable_if<="" (a="=b)," void="">::type> {
        static constexpr indexes<a> dispatch();
    };

    template<int a,="" int="" b="">
    struct expand_span_<a, b,="" typename="" std::enable_if<="" (a<b),="" void="">::type> {
        static constexpr decltype(combine</a,></int></a><a>(expand_span_<a+1, b="">::dispatch())) 
            dispatch();
    };

    template<int a,="" int="" b="">
    constexpr auto expand_span() -> decltype(expand_span_<a,b>::dispatch());
}

template <int a,="" int="" b=""> using span = decltype(expand_span<a,b>());

////////////////////////////////////////////////////////////////
// using indirect template arguments
template<typename> struct indirect_work { };

void test_indirect()
{
    indirect_work<indexes<1,2,3,4>> x;
    indirect_work<span<1,4>>        y;

    x = y; // x and y are of identical types
    static_assert(std::is_same<indexes<1,2,3,4>, span<1,4>>::value, "fact check");
}

////////////////////////////////////////////////////////////////
// using direct template arguments
template<int...> struct direct_work { };

// deduction alias:
template<int... direct=""> constexpr direct_work<direct...> deduction_helper(indexes<direct...>);
template <typename idx=""> using deduce = decltype(deduction_helper(Idx{}));

void test_direct()
{
    direct_work<1,2,3,4> x;
    deduce<indexes<1,2,3,4>> y;
    deduce<span<1,4>> z;

    static_assert(std::is_same<decltype(x), decltype(y)="">::value, "fact check");
    static_assert(std::is_same<decltype(x), decltype(z)="">::value, "fact check");
}

int main()
{
    test_indirect();
    test_direct();
}
</decltype(x),></decltype(x),></span<1,4></indexes<1,2,3,4></typename></direct...></direct...></int...></int...></indexes<1,2,3,4></span<1,4></indexes<1,2,3,4></typename></a,b></int></a,b></int></a+1,></a></a,></int></int></other...></a,></int></int...></type_traits>
Да, я заметил, что у proto есть те прекрасные типы функций, другой интуитивный синтаксисs - это T [N], чтобы сказать N раз T (кто больше использует необработанный массив!), и T *, чтобы сказать ноль или более T (опять же, кто использует собственный указатель?). Я не знаю, даст ли псевдоним / выражение объекта c ++ 14 что-то более красивое, напримерtuple abir
Там'Конечно, приоритетstd::function не содержащийvoid(int) MSalters
@MSalters aherm. Без шуток! Вы'повторяю, есть и другие библиотечные классы, которыетакже дон»не имеет удивительных интерфейсов! Ага. Хорошо, что'почему ты нене ожидал, чтоtuple моделиодинарный вызываемый и тыделать ожидатьstd::add_reference описать тип ссылки на массив, но неtuple (в любом случае, \ @abir: что?не так сtuple? Ср )array sehe
@ not-sehe Именно это я и делаю. Это почти так же, какwork пример. Если мы используем шаблоны, они очень похожи на LISP. напримерand_ abir
12

ия - находится в.[dcl.decl]

В основе этого синтаксиса лежат шесть фундаментальных конструкций, внутри которыхT может быть заменен любой из других конструкций в списке. [В следующих,(T) представляет список из нуля или более типов (которые могут заканчиваться на '...»), а также представляет список одного или нескольких типов.]

T // T
T* // pointer to T
T& // reference to T
T[n] // array of size 'n' of T
T C::* // pointer to C::member of type T
T (T) // function taking '(T)' and returning T

РЕДАКТИРОВАТЬТип специализации шаблона класса может быть заменен на любой:T

C<t> // specialization of class template C with arguments '<t>'
</t></t>

Существуют комбинации из вышеперечисленного, которые создают конструкции, которые имеют особое значение:

T (*)(T) // pointer to function taking '(T)' and returning T
T (C::*)(T) // pointer to C::member-function taking '(T)' and returning T

Кроме того, некоторые конструкции могут быть cv-квалифицированными:

const T // const T
T* const // const pointer to T
T C::* const // const pointer to C::member of type T

Не все комбинации приводят к допустимым типам. В соответствии с[basic.compound]можно использовать только следующие комбинации:

Составные типы могут быть созданы следующими способами:

массивы объектов данного типафункции, которые имеют параметры заданных типов и возвращают void или ссылки или объекты заданного типауказатели на void или объекты или функции (включая статические члены классов) заданного типассылки на объекты или функции данного типауказатели на нестатические члены класса, которые идентифицируют члены данного типа в объектах данного класса

Дополнительные ограничения упоминаются:

[dcl.ptr] нет указателей на ссылки

[dcl.ref] Не должно быть ссылок на ссылки, массивов ссылок и указателей на ссылки.

[dcl.mptr] Указатель на член не должен указывать на ... член со ссылочным типом или "cv void. "

[dcl.fct] Список параметров (void) эквивалентен пустому списку параметров. За исключением этого особого случая, void не должен быть типом параметра. ... Если тип параметра включает в себя тип формы «указатель на массив неизвестных границ T » или же "ссылка на массив неизвестных границ T » программа плохо сформирована. Функции не должны иметь тип возвращаемого типа массива или функции.

Некоторые из возможных конструкцийне могу использоваться в качестве аргументов шаблона. Когда вы явно указываете набор аргументов шаблона, компилятор должен проверить, что аргументы шаблона могут быть заменены параметрами шаблона, не приводя к 'неверный тип, В соответствии с[temp.deduct]\2следующие конструкции составляют недопустимые типы:

Вывод типа может завершиться ошибкой по следующим причинам:

Попытка создать массив с типом элемента void, типом функции или ссылочным типом или попытка создать массив с нулевым или отрицательным размером.

template <class t=""> int f(T[5]);
int I = f<int>(0);
int j = f<void>(0); // invalid array
</void></int></class>

Попытка использовать тип, который не является типом класса в определенном имени.

template <class t=""> int f(typename T::B*);
int i = f<int>(0);
</int></class>

Попытка использовать тип в части квалификатора квалифицированного имени, которое присваивает имя типу, если этот тип не содержит указанного члена или если указанный член не является типом, для которого требуется тип.

template <class t=""> int f(typename T::B*);
struct A {};
struct C { int B; };
int i = f<a>(0);
int j = f<c>(0);
</c></a></class>

Попытка создать указатель на ссылочный тип.

Попытка создать ссылку на ссылочный тип или ссылку на void.

Попытка создать "указатель на член T " когда T не тип класса.

template  int f(int T::*);
int i = f(0);

Попытка выполнить недопустимое преобразование либо в выражении аргумента шаблона, либо в выражении, используемом в объявлении функции.

template  int f(int);
int i2 = f(0); // can’t conv 1 to int*

Попытка создать тип функции, в которой параметр имеет тип void.

Попытка создать cv-квалифицированный тип функции.

РЕДАКТИРОВАТЬ: Это основано на C ++ 03, но также относится к C ++ 11 (который добавляет rvalue ссылочные типы)

Список фактически пропускает сами шаблоны. Тот'уместны вопросы:using t8 = tpl; MSalters
Вам не хватает функций Varargs. Они очень отличаются от шаблонных функций, и обаT foo(U..., ...) а такжеT foo(...) отличаются от.T foo(U...) rubenvb
Другие, о которых я знаю, это ссылки вроде:T&T&&T(&)(A...) массив какT[] abir
@rubenv: отредактировано, спасибо willj

Похожие вопросы