[英]Variadic variadic template templates, again
我已經看到例如在同一問題上的一個相關問題 ,但是我有一個不同的問題,我認為無法以任何其他方式解決。
這是any
函數,它計算模板參數包表示形式(類型列表) P
任何元素的一元謂詞 F
是否為true:
template <template <typename...> class F, typename P>
struct any;
template <
template <typename...> class F,
template <typename...> class C, typename E, typename... En
>
struct any <F, C <E, En...> > :
public _if <F <E>{}, _true, any <F, C <En...> > > { };
template <template <typename...> class F, template <typename...> class C>
struct any <F, C <> > : public _false { };
其中我的_true/_false
等效於std::integral_constant <bool, true/false>
,並且_if <C, T, E>
等效於typename std::conditional <C, T, E>::type
(詳細信息為與問題無關,請參見下文)。
例如,一個人可能會寫
template <typename...> struct pack { };
template <typename T> using is_int = eq <int, T>;
any <is_int, pack <int, void, float, double> >(); // evaluates to true
any <is_int, pack <char, void, float, double> >(); // evaluates to false
其中eq
等效於std::is_same
。
對二進制謂詞的擴展如下:
template <template <typename...> class F, typename P, typename Q>
struct any2;
template <
template <typename...> class F,
template <typename...> class C, typename E, typename... En,
template <typename...> class D, typename H, typename... Hn
>
struct any2 <F, C <E, En...>, D <H, Hn...> > :
public _if <F <E, H>{}, _true, any2 <F, C <En...>, D <Hn...> > > { };
template <
template <typename...> class F,
template <typename...> class C, typename Q
>
struct any2 <F, C <>, Q> : public _false { };
我們現在可以在哪里寫
typedef pack <int, void, float, double> A;
typedef pack <void, float, double, int> B;
typedef pack <void, float, double, double> C;
any2 <eq, A, B>(); // false
any2 <eq, A, C>(); // true
問題來了 。 我們可以擴展的方式來n
進制謂詞 ,在操作n
輸入“包”?
這個問題與前一個問題不同,因為每個輸入包同時需要一個元素來評估F <...>
。
這是一個虛構的嘗試:
template <template <typename...> class F, typename... P>
struct any_n;
template <
template <typename...> class F,
template <typename...> class... C, typename... E, typename... En
>
struct any_n <F, C <E, En...>...> :
public _if <F <E...>{}, _true, any_n <F, C <En...>...> > { };
template <
template <typename...> class F,
template <typename...> class C, typename... P
>
struct any_n <F, C <>, P...> : public _false { };
當然不會編譯。 因此,可以寫C <E, En...>...
嗎? 那么C, E, En
的類型是什么?
我懷疑答案是否定的。
這樣的語法將非常方便,例如在Scheme宏中。 過去,我已經編寫了此語法的C ++模板實現,最多支持兩個級別,將符號dots
或etc
用於...
但是獲得編譯器的支持是完全不同的(特別是如果您需要在同一天進行編譯)。
Clang 3.3和GCC 4.8.1都接受了您對any_n<>
定義,而沒有發出警告,這使我相信它是完全有效的,除了它是邏輯。
為什么不起作用?
以any_n<>
的定義方式,它要求每個包中除第一個元素外的所有元素都完全相同,因為在struct any_n <F, C <E, En...>...>
, En...
必須為每個擴展的C<>
參數包重復。
也就是說,考慮
template<typename...>
struct Pack;
typedef Pack<int, float, double, bool> A;
typedef Pack<void, float, double, bool> B;
typedef Pack<float, float, double, bool> C;
和
template<typename...>
struct SomeMetaFunction
{...};
實例化any_n<SomeMetaFunction, A, B, C>
成功綁定any_n<>
的模板參數,如下所示:
F => SomeMetaFunction
C => std::tuple
E... => [int, void, float]
F... => [float, double, bool]
根據其第二個專業。
嘗試實例化any_n<SomeMetaFunction, A, B, C, D>
,其中D被定義為
typedef std::tuple <char, int, double, bool> D;
如預期的那樣導致undefined any_n<>
錯誤。
怎么做
只需對any_n<>
的定義進行少量修改,就可以完全實現所需的any_n<>
。 這個想法是使用遞歸列表的概念,就像函數語言一樣。
首先,您需要一個元函數來將pack<a, b, c, ..., z>
轉換為pack<a, pack<b, c, ... z>>
。
template<typename...>
struct toRecursiveList;
//a recursive list already
template<template <typename...> class Pack, typename H, typename... T>
struct toRecursiveList<Pack<H, Pack<T...>>>
{
using type = Pack<H, Pack<T...>>;
};
//several elements
template<template <typename...> class Pack, typename H, typename... T>
struct toRecursiveList<Pack<H, T...>>
{
using type = Pack<H, Pack<T...>>;
};
//one element
template<template <typename...> class Pack, typename H>
struct toRecursiveList<Pack<H> >
{
using type = Pack<H, Pack<>>;
};
//empty
template<template <typename...> class Pack>
struct toRecursiveList<Pack<>>
{
using type = Pack<>;
};
//missing pack
template<typename H, typename... T>
struct toRecursiveList<H, T...>
{
template<typename...>
struct Pack;
using type = Pack<H, Pack<T...>>;
};
any_n<>
的基本情況可確保在必要時將參數在第一步轉換為遞歸列表。
template <template <typename...> class F, typename... P>
struct any_n :
public any_n<F, typename toRecursiveList<P>::type...>
{};
現在我們保證每個包最多包含兩個元素,因為如果沒有,則基本情況會將其轉換為該表示形式。 利用這個事實,主要的遞歸變得如下。
template <
template <typename...> class F,
template <typename...> class... C, typename... E, typename... En
>
struct any_n <F, C <E, En>...> : //two elements each, no need for double pack expansion on En
public _if <F <E...>{}, _true, any_n <F, typename toRecursiveList<En>::type...>>::type { };
// ^ ensures a recursive list is passed onto the next recursion step
遞歸防護保持不變。
template <
template <typename...> class F,
template <typename...> class C, typename... P
>
struct any_n <F, C <>, P...> : public _false { };
前面的示例any_n<SomeMetaFunction, A, B, C, D>
現在可以按預期進行編譯。
我將使用boost::mpl::zip_view
一次遍歷所有列表。 實際上,我認為鏈接中的示例正是您需要的,除了您需要find_if
而不是transform_view
find_if
。
#include <boost/mpl/zip_view.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/unpack_args.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/not_equal_to.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/and.hpp>
#include <iostream>
using namespace boost::mpl;
using namespace boost::mpl::placeholders;
template <class Predicate, class ... Sequences>
struct any_n
{
typedef zip_view<vector<Sequences...> > seq;
typedef typename not_<
typename boost::is_same<
typename find_if<
seq,
unpack_args<Predicate> >::type,
typename end<seq>::type>::type>::type type;
};
typedef not_equal_to<boost::is_same<_1, _2>,
boost::is_same<_2, _3> >pred1;
typedef or_<equal_to<_1, _2>,
equal_to<_2, _3> > pred2;
typedef any_n<pred1,
range_c<int,0,10>,
vector_c<unsigned, 1, 4, 2, 5>,
vector_c<short, 0, 0, 2, 7, 4> >::type found1;
typedef any_n<pred2,
range_c<int,0,10>,
vector_c<unsigned, 1, 4, 2, 5>,
vector_c<short, 0, 0, 2, 7, 4> >::type found2;
int main()
{
std::cout << std::boolalpha << found1() << ' ' << found2() << std::endl;
}
如果您不熟悉Boost的模板元編程方法(即Boost.TemplateMetaprogrammingLibrary ),那么這似乎有些令人不知所措(甚至非常不堪重負)。 我曾經(至少到目前為止)唯一一本關於編程的書是“ C ++模板元編程”,如果您對此內容感興趣,我強烈推薦它。
我發現這個問題尤其指向本書。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.