我很难将variadic模板用于以下问题。
假设所有谓词仿函数都是形式,
class Pred1 {
public:
Pred1( Args... ); // The signature Args... can vary class to class.
template <typename T>
bool operator()(T t);
};
鉴于这些仿函数,我想创建一个可变参数模板类,如果每个谓词的所有operator()都返回true,则返回true,即
template <typename... Preds>
class CombinePredAnd {
public:
template <typename T>
bool operator()(T t){
// returns true if all of the Preds( Args... ).operator()(t) returns true;
// Args... should be passed when CombinePredAnd is constructed.
}
};
对我来说,我不知道将参数传递给Preds的每个构造函数。 你能给我一些提示吗? 此外,如果您有更好的设计具有相同的功能,请告诉我。
答案 0 :(得分:5)
也许是这样的:
#include <tuple>
#include <type_traits>
template <std::size_t N, std::size_t I, typename Tuple>
struct evaluate_all
{
template <typename T>
static bool eval(T const & t, Tuple const & preds)
{
return std::get<I>(preds)(t)
&& evaluate_all<N, I + 1, Tuple>::eval(t, preds);
}
};
template <std::size_t N, typename Tuple>
struct evaluate_all<N, N, Tuple>
{
template <typename T>
static bool eval(T const &, Tuple const &)
{
return true;
}
};
template <typename ...Preds>
struct conjunction
{
private:
typedef std::tuple<Preds...> tuple_type;
tuple_type preds;
public:
conjunction(Preds const &... p) : preds(p...) { }
template <typename T>
bool operator()(T const & t) const
{
return evaluate_all<sizeof...(Preds), 0, tuple_type>::eval(t, preds);
}
};
template <typename ...Preds>
conjunction<typename std::decay<Preds>::type...> make_conjunction(Preds &&... preds)
{
return conjunction<typename std::decay<Preds>::type...>(std::forward<Preds>(preds)...);
}
<强>用法:强>
auto c = make_conjunction(MyPred(), YourPred(arg1, arg2, arg3));
if (c(10)) { /* ... */ }
示例:强>
#include <iostream>
typedef int T;
struct Pred1
{
int a;
Pred1(int n) : a(n) { }
bool operator()(int n) const { return n >= a; }
};
struct Pred2
{
int a;
Pred2(int n) : a(n) { }
bool operator()(int n) const { return n <= a; }
};
int main()
{
auto c = make_conjunction(Pred1(1), Pred2(3));
std::cout << "1: " << c(1) << "\n"
<< "5: " << c(4) << "\n";
}
注意:您可以进行&#34;结合&#34;这种方法的一部分也是参数化的,因此只需插入std::logical_and
或std::logical_or
就可以得到连词和析取。
答案 1 :(得分:0)
以下是Kerrek SB的替代解决方案:
#include <tuple>
#include <type_traits>
#include <cstdlib>
template <typename HeadPred, typename ...TailPreds>
struct CombinePredAnd
{
template<typename H, typename ...Ts>
explicit CombinePredAnd(H const & h, Ts const &...ts)
: _preds(h, ts...){}
template <typename T>
bool operator()(T t){
return eval(t,_preds);
}
private:
template<typename T, size_t I = 0, typename ...Ps>
typename std::enable_if<sizeof ...(Ps) == I,bool>::type
static eval(T t, std::tuple<Ps...>) {
return true;
}
template<typename T, size_t I = 0, typename ...Ps>
typename std::enable_if<sizeof ...(Ps) != I,bool>::type
static eval(T t, std::tuple<Ps...> const & preds) {
auto const & pred = std::get<I>(preds);
return pred(t) && eval<T,I + 1>(t,preds);
}
std::tuple<HeadPred, TailPreds...> _preds;
};
这可以通过Kerrek SB建议的通用方式推广如下 任意谓词仿函数的连接或分离 通过选择连接或析取来参数化。一个测试程序 附加,使用gcc 4.7.2和clang 3.2构建:
#include <tuple>
#include <type_traits>
#include <functional>
#include <cstdlib>
template <class AndOrOr, typename HeadPred, typename ...TailPreds>
struct dis_or_con_join
{
static_assert(
std::is_same<AndOrOr,std::logical_and<bool>>::value ||
std::is_same<AndOrOr,std::logical_or<bool>>::value,
"AndOrOr must be std::logical_and<bool> or std::logical_or<bool>");
template<typename H, typename ...Ts>
explicit dis_or_con_join(H const & h, Ts const &...ts)
: _preds(h, ts...){}
template <typename T>
bool operator()(T t){
return eval(t,_preds);
}
private:
static const bool conjunction =
std::is_same<AndOrOr,std::logical_and<bool>>::value;
template<typename T, size_t I = 0, typename ...Ps>
typename std::enable_if<sizeof ...(Ps) == I,bool>::type
static eval(T t, std::tuple<Ps...>) {
return conjunction;
}
template<typename T, size_t I = 0, typename ...Ps>
typename std::enable_if<sizeof ...(Ps) != I,bool>::type
static eval(T t, std::tuple<Ps...> const & preds) {
auto lamb = conjunction ?
[](bool b){ return b; } :
[](bool b){ return !b; };
auto const & pred = std::get<I>(preds);
return lamb(lamb(pred(t)) && lamb(eval<T,I + 1>(t,preds)));
}
std::tuple<HeadPred, TailPreds...> _preds;
};
template<typename HeadPred, typename ...TailPreds>
using conjunction =
dis_or_con_join<std::logical_and<bool>,HeadPred,TailPreds...>;
template<typename HeadPred, typename ...TailPreds>
using disjunction =
dis_or_con_join<std::logical_or<bool>,HeadPred,TailPreds...>;
// Test...
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
// For various predicates with various constructors...
template<typename T>
struct is_in_list
// Stores an arbitrary sized list of its type T constructor arguments
// and then with tell us whether any given T is in its list
{
is_in_list(initializer_list<T> il)
: _vals(il.begin(),il.end()){}
bool operator()(T t) const {
return find(_vals.begin(),_vals.end(),t) != _vals.end();
}
list<T> _vals;
};
int main()
{
is_in_list<char> inl03 = {'\0','\3'};
is_in_list<long> inl013 = {0,1,3};
is_in_list<float> inl0123 = {0.0f,1.0f,2.0f,3.0f};
conjunction<is_in_list<char>,is_in_list<long>,is_in_list<float>>
conj{inl03,inl013,inl0123};
disjunction<is_in_list<char>,is_in_list<long>,is_in_list<float>>
disj{inl03,inl013,inl0123};
cout << "conjunction..." << endl;
cout << 1 << " is " << (conj(1) ? "" : "not ")
<< "in all the lists" << endl;
cout << 0 << " is " << (conj(0) ? "" : "not ")
<< "in all the lists" << endl;
cout << 3 << " is " << (conj(3) ? "" : "not ")
<< "in all the lists" << endl;
cout << "disjunction..." << endl;
cout << 1 << " is in " << (disj(1) ? "at least one " : "none ")
<< "of the lists" << endl;
cout << 2 << " is in " << (disj(2) ? "at least one " : "none ")
<< "of the lists" << endl;
cout << 3 << " is in " << (disj(3) ? "at least one " : "none ")
<< "of the lists" << endl;
cout << 4 << " is in " << (disj(4) ? "at least one " : "none ")
<< "of the lists" << endl;
return 0;
}
可能不清楚的一句话:
return lamb(lamb(pred(t)) && lamb(eval<T,I + 1>(t,preds)));
利用等价:
P or Q = not(not(P) and not(Q))
输出: -
conjunction...
1 is not in all the lists
0 is in all the lists
3 is in all the lists
disjunction...
1 is in at least one of the lists
2 is in at least one of the lists
3 is in at least one of the lists
4 is in none of the lists