可变模板:选择具有适当方法的元组元素类型
Variadic templates: choose the tuple element type that has a proper method
我有一个这样的类:
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结果||
类似这样的东西:
// 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);
首先,我们需要一个元函数,它可以告诉我们表达式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);
这将为CanEvaluate<InputType>::eval<T>::value == true
所在的Types
中的所有类型T
调用Evaluate
,并返回结果的||。
我不确定你到底想做什么。以下是我认为的解决方案:
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);
}
};
相关文章:
- C++:TypeDef使用元组
- Pybind11:将元组列表从Python传递到C++
- 重载元组索引运算符-C++
- 在C++中,如何通过几种类型从元组中选择多个元素
- 枚举元组类型的最佳方法?
- 如何使用返回第 n 个元素的方法创建元组
- 当元组给出参数时,如何检查方法是否存在?
- 一种从元组/数组获取参数包的方法
- 如果元组足够大,请使用sfinae启用方法
- 有没有一种方法可以将左值和右值的列表分别转换为具有引用类型和完整类型的元组
- 使用凤凰访问增强::元组的简单方法
- 正在拆包方法参数的元组
- 将元组传递给函数并让它返回数字列表的最佳方法
- C++11 在运行时不使用 switch 为元组编制索引的方法
- 填充一个boost元组以替代此方法
- 返回 vector<pair<int,int>> & from c++ 方法到 python 使用 swig typemap 的元组列表
- 可变模板:选择具有适当方法的元组元素类型
- c++元编程—创建包含模板化方法的所有变体的元组
- 在元组上操作的递归可变模板方法
- 将签名来自元组解包的静态方法的地址作为回调传递