是否可能有一个非递归的at_c实现?
Is it possible to have a non recursive at_c implementation?
很久以前,我看到过一个从类型序列/值序列中获取最后一个值/类型的非递归实现。它有一个很好的属性,即实例化的模板数量与序列包含的元素数量无关(并且是恒定的)。
实现很简单,如下所示
// a struct that eats anything and everything
struct eat { template<class T> eat(T&&) {} };
// generates V matching with U
template<class U, class V> struct match { using type = V; };
template<class... X> struct back_
{
template<class U>
static U&& get(typename match<X, eat>::type..., U&& u)
{
return static_cast<U&&>(u); // forward
}
};
// simple macro to avoid repetition for trailing return type.
#define RETURNS(exp) -> decltype(exp) { return exp; }
// get the last value in meta O(1)
template<class T, class... Ts>
auto back(T&& t, Ts&&... ts) RETURNS( back_<Ts...>::get(static_cast<T&&>(t), static_cast<Ts&&>(ts)...))
它使用了一个简单的事实,给定一个可变类型X...
,编译器可以非递归地生成另一个类型T
,与X
的数量一样多。
所以,我想知道是否有一种方法可以扩展它以实现at_c
或nth
函数,具有恒定数量的实例化模板(与元素数量无关)。
它也可以被表述为,给定可变类型X...
和一些整数N
,是否有可能非递归地生成由N
元素组成的X...
的子序列?
std::cout << back((int)(0),
(int*)(0),
(int**)(0),
(int***)(0),
(int****)(0),
(int*****)(0),
(int******)(0),
(int*******)(0),
1) << std::endl;
======================================================
nm -C que | fgrep eat
080489e2 W eat::eat<int*******>(int*******&&)
080489dc W eat::eat<int******>(int******&&)
080489d6 W eat::eat<int*****>(int*****&&)
080489d0 W eat::eat<int****>(int****&&)
080489ca W eat::eat<int***>(int***&&)
080489c4 W eat::eat<int**>(int**&&)
080489be W eat::eat<int*>(int*&&)
080489b8 W eat::eat<int>(int&&)
080489e2 W eat::eat<int*******>(int*******&&)
080489dc W eat::eat<int******>(int******&&)
080489d6 W eat::eat<int*****>(int*****&&)
080489d0 W eat::eat<int****>(int****&&)
080489ca W eat::eat<int***>(int***&&)
080489c4 W eat::eat<int**>(int**&&)
080489be W eat::eat<int*>(int*&&)
080489b8 W eat::eat<int>(int&&)
080489e7 W int&& back_<int*, int**, int***, int****, int*****, int******, int*******, int>::get<int>(eat, eat, eat, eat, eat, eat, eat, eat, int&&)
080489e7 W _ZN5back_IJPiPS0_PS1_PS2_PS3_PS4_PS5_iEE3getIiEEOT_3eatSB_SB_SB_SB_SB_SB_SB_SA_
我的解决方案:))编译gcc 4.6.4 -std=c++0x
主要思想是,对于任意'i'和0,1,2,…n-1(其中n> i)(0 ^ i), (1 ^ i),…(j ^ i)…, ((n-1) ^ I)——是唯一序列,且只有在' I '处的值位置为零。
它不是O(1)解,而是O(log(n))解。但它是基于c++ 14的make_index_sequence。如果编译器在0(1)处编译make_index_sequence,那么我的解决方案也变成了0(1)。
#include <cstddef>
#include <iostream>
#include <type_traits>
namespace mpl
{
// C++14 index_sequence struct
template< int ... i >
struct index_sequence
{
typedef index_sequence type;
typedef int value_type;
static constexpr std::size_t size()noexcept{ return sizeof...(i); }
};
namespace details
{
#if 1
template< int s, typename T, typename U> struct concate_c;
template<int s, int ...i, int ...j>
struct concate_c< s, index_sequence<i...>, index_sequence<j...> >
: index_sequence<i..., (j + s ) ... > {};
template< int s, typename T, typename U> struct concate : concate_c< s, typename T::type, typename U::type > {};
template< int n>
struct make_index_sequence : concate< n / 2,
make_index_sequence< n / 2 >,
make_index_sequence< n - n / 2 >
>{};
#else
template< typename T, typename U> struct concate_c;
template< int ...i, int ...j>
struct concate_c< index_sequence<i...>, index_sequence<j...> >
: index_sequence<i..., (j + sizeof...(i) ) ... > {};
template< typename T, typename U> struct concate : concate_c< typename T::type, typename U::type > {};
template< int n>
struct make_index_sequence : concate<
make_index_sequence< n / 2 >,
make_index_sequence< n - n / 2 >
>{};
#endif
template<> struct make_index_sequence<0> : index_sequence<>{};
template<> struct make_index_sequence<1> : index_sequence<0>{};
} // namespace details
template< int n> struct make_index_sequence : details::make_index_sequence<n> {};
template< typename ...Args>
struct make_index_sequence_for : make_index_sequence< sizeof...(Args) > {};
// helper for at_c, I - index_sequence,
template< typename I, typename ...p >
struct at_ch;
// only zero index have `type`.
template< int i, typename T> struct id{};
template< typename T>struct id<0,T>{ typedef T type;};
// based from all parameters.
template< typename ...T> struct base_all : T... {};
template< int ... i, typename ...p>
struct at_ch< index_sequence<i...>, p... >
{
struct base : base_all< id<i,p> ... > {};
typedef typename base::type type;
};
// 0 1 2 3 4 5 6 7 8 9
// 0: 0 1 2 3 4 5 6 7 8 9
// 1: 1 0 3 2 5 4 7 6 9 8
template< int i, typename I>
struct xor_index_sequence;
template< int i, int ...k>
struct xor_index_sequence< i, index_sequence<k...> > : index_sequence< (k xor i) ... > {};
template< int i, typename ...T>
struct at_c: at_ch<
typename xor_index_sequence< i,
typename make_index_sequence< sizeof...(T)> ::type
>::type,
T...
> {};
}
int main()
{
typedef mpl::at_c< 2, int, double , float >::type G;
static_assert( std::is_same<G, float>::value ,"!");
return 0;
}
相关文章:
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 如何处理来自核心指南检查器的关于gsl::at的静态分析警告
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 为什么'std::array::at()'没有实现为模板函数?
- 测试容器是否实现.at()成员访问/ std::sort兼容的正确方法
- 为什么不为' at '和' operator[] '实现异构比较查找