zdebyman
zdebyman

Reputation: 650

How to check if parameter pack has exact types in an exect order

I have a function checkTO which takes a function pack as a parameter and i want to know if this pack contains int, char and bool types and in this particular order but same time they can be placed anywhere. Other arguments of the same type are allowed, i just need to know if those 3 in this order are present or not.

I have this example which does the job.

#include <iostream>


static bool foundInt = false;
static bool foundChar = false;
static bool foundBool = false;
static bool hasTO = false;

void check() {

}

template <typename T>
void check(T value) {      
    if (hasTO) {
        return;
    }

    if (foundInt && foundChar && foundBool) {
        hasTO = true;
        return;
    }

    if (!foundInt || !foundChar) {
        hasTO = false;
        return;
    }

    hasTO = std::is_same<T, bool>::value;
}

template <typename First, typename... Rest>
void check(First firstValue, Rest... rest) {
    if (!foundInt) {
        if (std::is_same<First, int>::value) {
            foundInt = true;
        }
        check(rest...);
    } else if (!foundChar) {
        if (std::is_same<First, char>::value) {
            foundChar = true;
        } else {
            // args have to be in a special order
            if (!std::is_same<First, int>::value) {
                foundInt = false;
            }
        }
        check(rest...);
    } else  if (!foundBool) {
        if (std::is_same<First, bool>::value) {
            foundBool = true;
            hasTO = true;
        } else {
            // args have to be in a special order
            foundInt = false;
            foundChar = false;
        }
        check(rest...);
    }

    check(rest...); 
}

template <typename... T_values>
bool checkTO(const T_values&... args) {
    foundInt = false;
    foundChar = false;
    foundBool = false;
    hasTO = false;
    check(args...);
    return hasTO;
}

int main()
{
  int a = 1;
  char b = 'c';
  bool c = true;
  float d = 1.1;
  float d1 = 1.1;
  float d2 = 1.2;

  std::cout << "TRUE1: " << checkTO() << std::endl;
  std::cout << "TRUE1: " << checkTO(a, b, c) << std::endl;
  std::cout << "TRUE2: " << checkTO(a, a, b, c) << std::endl;
  std::cout << "TRUE3: " << checkTO(a, a, b, c, c) << std::endl;
  std::cout << "TRUE4: " << checkTO(d, a, b, c, c) << std::endl;
  std::cout << "TRUE5: " << checkTO(a, b, d1, a, b, c, d2) << std::endl;
  std::cout << "TRUE6: " << checkTO(d1, d2, a, a, a, b, c) << std::endl;
  std::cout << "TRUE7: " << checkTO(a, b, c, d1, d2, a, a, b, a, c) << std::endl;
  std::cout << "FALSE1: " << checkTO(c, a, b) << std::endl;
  std::cout << "FALSE2: " << checkTO(b, c, a) << std::endl;
  std::cout << "FALSE3: " << checkTO(d1, a, b) << std::endl;
  std::cout << "FALSE4: " << checkTO(a, b, d1, c) << std::endl;

}

Output:

TRUE1: 0
TRUE1: 1
TRUE2: 1
TRUE3: 1
TRUE4: 1
TRUE5: 1
TRUE6: 1
TRUE7: 1
FALSE1: 0
FALSE2: 0
FALSE3: 0
FALSE4: 0

I really hate this solution as its not scalable (what if i need to check 44 params?) and global variables. Is there a smarter way?

Upvotes: 1

Views: 53

Answers (1)

Daniel Jour
Daniel Jour

Reputation: 16156

template<typename...T> struct check;
template<typename A, typename...B> struct check<A,B...> {
    static constexpr bool pass = check<B...>::pass;
};
template<typename...R> struct check<int,char,bool,R...> {
    static constexpr bool pass = true;
};
template<> struct check<> {
    static constexpr bool pass = false;
};

template<typename... T>
constexpr bool check_this(T...) { return check<T...>::pass; }

This uses a template struct with some template specializations:

  • One which "iterates" over the parameter pack
  • One which matches when it finds the requested sequence
  • One which matches the "base case" (e.g. no match found)

Live example on ideone which uses your main (and renames my check_this to checkTO). Passes all tests except the first ... why should checkTO() return true??

Upvotes: 1

Related Questions