2

I want to create a program that has array with hardcode elements L (e.g.:1,2,3,3), and use template variable arguments to check of the elements is sorted, if not sorted, it will be failed to compile at static_assert, but now the program cannot compile at all:

#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;
}

the compile error says:

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{

what is the reason? Is it just syntax error in template? or this idea is not possible?if not possible,is there other ways to check if array is sorted at compile time?

2
  • Constexpr function should be much simpler. Commented Jan 19, 2016 at 1:47
  • Both g++ and clang++ give me an error about the "redeclaration" of the template, which is the important mistake. Commented Jan 19, 2016 at 2:27

4 Answers 4

4

You need the partial template specialization.

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, "");
}
Sign up to request clarification or add additional context in comments.

Comments

2

Your syntax is wrong for partial template specialization

#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;
}

Online Demo at Coilru

Comments

1

You are trying to use partial template specialization. This allows to make multiple definitions for a class template.

But even with this feature, you have to create only one declaration of the type. The declaration is something like this:

template<int... I>
struct s;

You can even combine it with a definition:

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

Behind this declaration of s, you can add other definitions. But it is not allowed to add declarations which differs from the first. To add definitions (and no declarations), you have to add template parameters to the name of the type. Note the <10> after the name in the following definition. The definition is only used for the type s<10>:

template<>
struct s<10> {};

You can also use more generic definitions. The following definitions is only used for s<x> where x is some integer. It will not be used for types which have more then one template parameter.

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

I would implement your s using C++11 this way:

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();};
};

Comments

1

You do not need elaborate solution for this. First you need to define proper is_sorted since before C++20 is_sorted is not constexpr and then just use it.

#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}));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.