I have a class like this:
template <typename... Types>
class Evaluator
{
public:
template <typename... Types>
Evaluator(Types... args)
{
list = std::make_tuple(args...);
}
template <typename T>
bool Evaluate(const T& input)
{
// based on a specific input type T, here I want to call
// Evaluate(input) for a specific element in the tuple. i.e. the
// element that has method Evaluate, for which Evaluate(input) compiles
return std::get<0>(list).Evaluate(input);
}
private:
std::tuple<Types...> list;
};
Update The function could return false for instances that don't have proper "Evaluate(input) -> bool" function and is evaluated for all matching with bool result ||
First of all, we need a metafunction which can tell us whether the expression declval<T>().Evaluate(input)
makes sense for a given type T
.
We can use SFINAE and decltype in order to do so:
template<class ... Arguments>
struct CanEvaluate
{
template<class T, class Enable = void>
struct eval : std::false_type {};
template<class T>
struct eval<T,
decltype( void( std::declval<T>().Evaluate(std::declval<Arguments>() ... ) ) ) > : std::true_type {};
};
Now we can write a single class MultiEvaluateFromTuple
.
template<class TupleType, class ... InputTypes>
struct MultiEvaluateFromTuple
{
private:
template<int I,int S,class Dummy = void>
struct CheckEvaluate : CanEvaluate<InputTypes...>::template eval<typename std::tuple_element<I,TupleType>::type> {};
//We need this because we can't instantiate std::tuple_element<S,TupleType>
template<int S> struct CheckEvaluate<S,S> : std::false_type {};
// Forward to the next element
template<int I,int S, class Enabler = void>
struct Impl {
static bool eval(const TupleType & r, const InputTypes & ... input) {
return Impl<I+1,S>::eval(r,input...);
}
};
// Call T::Evalute()
template<int I,int S>
struct Impl<I,S, typename std::enable_if<CheckEvaluate<I,S>::value>::type> {
static bool eval(const TupleType & r, const InputTypes & ... input) {
bool Lhs = std::get<I>(r).Evaluate(input...);
bool Rhs = Impl<I+1,S>::eval(r,input...);
return Lhs || Rhs;
}
};
//! Termination
template<int S>
struct Impl<S,S> {
static bool eval(const TupleType & r, const InputTypes & ... input) {
return false;
}
};
public:
static bool eval(const TupleType & r,const InputTypes & ... input) {
return Impl<0, std::tuple_size<TupleType>::value>::eval(r,input...);
}
};
Usage:
return MultiEvaluateFromTuple<std::tuple<Types...>,T>::eval(list,input);
This will call Evaluate
for all the types T
in Types
for which CanEvaluate<InputType>::eval<T>::value == true
, and return the || of the results.