1

我有这样的课:

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;

};

更新对于没有正确“Evaluate(input) -> bool”函数的实例,该函数可能会返回false,并针对所有与bool结果匹配的情况进行评估||

4

3 回答 3

3

像这样的东西:

// Unspecialized form, when the current element doesn't match. Tries the next one.
template <typename Tuple, int I, typename Argument, typename = void>
struct CallEvaluate : CallEvaluate<Tuple, I+1, Argument> {};

// Termination case, when the end of the tuple was reached. Has no operator () and will
// cause a compilation error.
template <typename Tuple, typename Argument>
struct CallEvaluate<Tuple, std::tuple_size<I>::value, Argument> {}; // no type fits

// Termination case, when the call std::get<I>(list).Evaluate(input) is valid.
template <typename Tuple, int I, typename Argument>
struct CallEvaluate<Tuple, I, Argument,
                    decltype(void(
                      std::declval<typename std::tuple_element<Tuple, I>::type>()
                        .Evaluate(std::declval<const Argument&>())))> {
   bool operator ()(const Tuple& list, const Argument& input) const {
     return std::get<I>(list).Evaluate(input);
   }
};


// Use:
CallEvaluate<decltype(list), 0, T>()(list, input);
于 2013-08-27T14:38:54.957 回答
2

首先,我们需要一个元函数,它可以告诉我们表达式declval<T>().Evaluate(input)对于给定类型是否有意义T

我们可以使用 SFINAE 和 decltype 来做到这一点:

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

现在我们可以编写一个类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...);
    }
};

用法:

return MultiEvaluateFromTuple<std::tuple<Types...>,T>::eval(list,input);

这将调用forEvaluate中的所有类型T,并返回 || 的结果。TypesCanEvaluate<InputType>::eval<T>::value == true

于 2013-08-27T15:48:29.887 回答
0

我不确定你到底想做什么。以下是我认为的解决方案:

template <typename... Types>
class Evaluator
{
private:
    std::tuple<Types...> list;

    template <typename T>
    struct has_evaluator
    {
        typedef char yes;
        typedef char no[2];

        template <typename C, C>
        struct S;

        template <typename U>
        yes& check(S<bool T::*, &T::Evaluate>*);

        template <typename U>
        no& check(...);

        static const bool value = sizeof(check<T>(nullptr)) == sizeof(char);
    };
public:
    template <typename... Args>
    Evaluator(Args&&... args) : list(std::make_tuple(std::forward<Args>(args)...))
    { }

    template <typename T,
              typename = typename std::enable_if<
                  has_evaluator<typename std::tuple_element<0, decltype(list)>::type>::value>::type>
    auto Evaluate(const T& input) -> decltype(std::get<0>(list).Evaluate(input), bool())
    {
        return std::get<0>(list).Evaluate(input);
    }
};
于 2013-08-27T15:44:20.023 回答