Template parameter pack's parameters to T

I have a map of components. Components are POD types that have some data. Each component has a unique identifier. The map can own only one component of a given type at any time. As such, I want to be able to query the map's owned components. This is the code I'm using to accomplish this:

template <typename T>
bool has()
{
    auto found = map.find(T::tag);
    if (found != map.end()) return true;
    else return false;
}

This would result in awkward code like: something.has<Component<int>>() && something.has<Component<float>>() ... etc;

In order to make the code less messy, I want to make use of variadic templates.

template <typename T, typename... Args>
bool hasz()
{
    has<T>();
    has<Args>()...; /* expected ‘;’ before ‘...’ token */
}

Shouldn't has<Args>()... expand to (pseudo) has<Args[0]>(), has<Args[1]>(), etc... (which would be legal syntax)? And is it possible to do this at all?

Upvotes: 1

Views: 151

Answers (2)

Manu343726
Manu343726

Reputation: 14174

Yes, you only have to call the function recursivelly:

template <typename T>
bool has()
{
    return map.end() != map.find(T::tag);
}

template <typename T, typename... Args>
bool has()
{
    return has<T>() && has<Args...>();
}

How it works?

You have two versions of the function: One with one parameter, and one with n parameters. The first is used as the base case, and the later is used as the recursive case.
So if you do this:

has<bool,int,char,float>();

The trace is:

call to has<bool,int,char,float>() (Call to recursive case)
call to has<bool,int,char>() (Call to recursive case)
call to has<bool,int>() (Call to recursive case)
call to has<bool>() (Call to base case)

NOTE: Of course this example does not work really, because the types I used in the example don't have a ::tag member. Its only an example of the call trace indeed. In addition, I have simplified the trace to not overcomplicate the example. The true trace will be:

call to has<bool,int,char,float>() (Call to recursive case)
....call to has<bool>() (Call to base case) //left side of the &&
....call to has<int,char,float>() (Call to recursive case) //right side of the &&
........call to has<int>() (Call to base case) //left side of the &&
........call to has<char,float>() (Call to recursive case) //right side of the &&
............call to has<char>() (Call to base case) //left side of the &&
............call to has<float>() (Call to base case) //right side of the &&

Upvotes: 7

zch
zch

Reputation: 15278

You can use std::min:

#include<algorithm>

template <typename... Args>
bool hasz()
{
    return std::min({has<Args>()...});
}

Note that this doesn't have short-circuit behavior - it will always evaluate has<Args> for all arguments. If it's the problem, then use recursive version.

Upvotes: 2

Related Questions