как проверить, сортируется ли жесткий массив int во время компиляции с использованием рекурсии шаблона?

Я хочу создать программу, которая имеет массив с жесткими элементами L (например: 1,2,3,3) и использовать аргументы переменных шаблона для проверки сортировки элементов, если они не отсортированы, она не сможет скомпилироваться в static_assert , но теперь программа вообще не может скомпилироваться:

#include <stdio.h>
#include <vector>
template<int first,int second,int... args>
struct s{
    enum{e=first<=second && s<second,args...>::e};
};

template<int first,int second>
struct s{
    enum{e=first<=second};
};
#define L 1,2,3,3
//static_assert(s<L>::e!=0,"");
int a[]={L};
int main(){
    printf("%d\n",s<L>::e);
    return 0;
}

ошибка компиляции говорит:

abc.cpp:5:29: error: too few template arguments for class template 's'
    enum{e=first<=second && s<second,args...>::e};
                        ^
abc.cpp:5:29: note: in instantiation of template class 's<3, 3>' requested here
    enum{e=first<=second && s<second,args...>::e};
                        ^
abc.cpp:5:29: note: in instantiation of template class 's<2, 3, 3>' requested here
    enum{e=first<=second && s<second,args...>::e};
                        ^
abc.cpp:16:19: note: in instantiation of template class 's<1, 2, 3, 3>' requested here
    printf("%d\n",s<L>::e);
              ^
abc.cpp:4:8: note: template is declared here
    struct s{

какова причина? Это просто синтаксическая ошибка в шаблоне? или эта идея невозможна? Если это невозможно, есть ли другие способы проверить, отсортирован ли массив во время компиляции?


person ggrr    schedule 19.01.2016    source источник
comment
Функция constexpr должна быть намного проще.   -  person cqdjyy01234    schedule 19.01.2016
comment
И g++, и clang++ выдают ошибку о переобъявлении шаблона, что является важной ошибкой.   -  person aschepler    schedule 19.01.2016


Ответы (4)


Вам нужна специализация частичного шаблона.

template<int... Args>
struct IsSorted {
    static constexpr bool value = true;
};

template<int A, int B, int... Args>
struct IsSorted<A, B, Args...> {
    static constexpr bool value = A <= B && IsSorted<B, Args...>::value;
};

int main() {
    static_assert(IsSorted<>::value, "");
    static_assert(IsSorted<1>::value, "");
    static_assert(IsSorted<1, 2>::value, "");
    static_assert(!IsSorted<2, 1>::value, "");
    static_assert(IsSorted<1, 2, 3>::value, "");
    static_assert(!IsSorted<1, 3, 2>::value, "");
}
person cqdjyy01234    schedule 19.01.2016

Ваш синтаксис неверен для частичной специализации шаблона

#include <stdio.h>
#include <vector>
template<int first,int second,int... args>
struct s{
    enum{e=first<=second && s<second,args...>::e};
};

template<int first,int second>
struct s<first, second>{ // <----- <first, second> here
    enum{e=first<=second};
};

#define L 1,2,3,3
#define L2 1,2,4,3
//static_assert(s<L>::e!=0,"");
int a[]={L};
int main(){
    printf("%d\n",s<L>::e);
    printf("%d\n",s<L2>::e);
    return 0;
}

Онлайн-демонстрация на Coilru

person Bryan Chen    schedule 19.01.2016

Вы пытаетесь использовать частичную специализацию шаблона. Это позволяет сделать несколько определений для шаблона класса.

Но даже с этой функцией вам нужно создать только одно объявление типа. Декларация примерно такая:

template<int... I>
struct s;

Вы даже можете комбинировать его с определением:

template<int... I>
struct s {};

За этим объявлением s вы можете добавить другие определения. Но нельзя добавлять объявления, отличающиеся от первого. Чтобы добавить определения (а не объявления), вы должны добавить параметры шаблона к имени типа. Обратите внимание на <10> после имени в следующем определении. Определение используется только для типа s<10>:

template<>
struct s<10> {};

Вы также можете использовать более общие определения. Следующие определения используются только для s<x>, где x — некоторое целое число. Он не будет использоваться для типов, которые имеют более одного параметра шаблона.

template<int I>
struct s<I> {}

Я бы реализовал ваш s с помощью С++ 11 следующим образом:

template<int... args>
struct s {
    static constexpr bool value() {return true;}
};

template<int first, int second, int... args>
struct s<first, second, args...> {
    static constexpr bool value() {return first <= second && s<second,args...>::value();};
};
person JojOatXGME    schedule 19.01.2016

Вам не нужно сложное решение для этого. Сначала вам нужно определить правильный is_sorted, поскольку до C++20 is_sorted не был constexpr, а затем просто использовать его.

#define L1 1,2,3,3
#define L2 1,2,1,3

template<typename T>
constexpr bool c_is_sorted(const std::initializer_list<T>& il){
    for(auto it= il.begin(); it!=il.end()-1;it++){
        if (*(it+1)<*it) {
            return false;
        }
    }
    return true;
}

int main(){
    static_assert(c_is_sorted({L1}));
    static_assert(!c_is_sorted({L2}));
}
person NoSenseEtAl    schedule 23.04.2018