我想知道如何得到这样的东西:
写
copy(a, b, 2, 3)
然后获取
a[2] = b[2];
a[3] = b[3];
a[4] = b[4];
我知道C #defines不能递归使用以获得该效果。但我正在使用C ++,所以我认为模板元编程可能是合适的。
我知道有一个Boost库,但我只想要那个“简单”的技巧,而Boost太“混乱”了。
答案 0 :(得分:25)
最直接的解决方案是编写一个循环,其中包含起始值和结束值:
for(int i = 2; i <= 4; i++) {
a[i]=b[i];
}
我认为这比任何类型的模板/运行时调用混合更好:编写的循环对于编译器的优化器来说是完全清楚的,并且没有任何级别的函数调用来挖掘只是为了看看发生了什么。
答案 1 :(得分:24)
C ++元编程是递归的。
从递归的角度考虑你的问题。实施终端案例和非终端案例。
您的终端案例可以是0或1。将限制作为模板参数传递。使用结构/类,因为它们允许部分特化和其他整洁的东西:
template<int from, int to>
struct copy {
static void apply(source, destination) {
source[from] = destination[from];
copy<from+1,to>:: apply(source, destination);
}
};
// Terminal case
template<int from>
struct copy<from, from> {
static void apply(source, destination) {
source[from] = destination[from];
}
};
答案 2 :(得分:3)
您可以执行以下操作。根据您使用的编译器和优化设置,您可以 获得您正在寻找的效果。
请注意,对于像char这样的小对象,它可能比std::copy
或memcpy
慢,而对于较大的对象,与副本相比,循环的成本可能微不足道无论如何。
#include <cstddef>
template<std::size_t base, std::size_t count, class T, class U>
struct copy_helper
{
static void copy(T dst, U src)
{
dst[base] = src[base];
copy_helper<base + 1, count - 1, T, U>::copy(dst, src);
}
};
template<std::size_t base, class T, class U>
struct copy_helper<base, 0, T, U>
{
static void copy(T, U)
{
}
};
template<std::size_t base, std::size_t count, class T, class U>
void copy(T dst, U src)
{
copy_helper<base, count, T, U>::copy(dst, src);
}
template void copy<5, 9, char*, const char*>(char*, const char*);
#include <iostream>
#include <ostream>
int main()
{
const char test2[] = " , World\n";
char test[14] = "Hello";
copy<5, 9>(test, test2);
std::cout << test;
return 0;
}
答案 3 :(得分:2)
重要的是要意识到编译器非常智能,并且使用模板元编程来欺骗循环可能会让你更进一步,它会让你前进。
为了最大限度地利用优化:密切关注反汇编。这将有助于教你更多的问题。
请注意,就像约翰内斯所说的那样:如果编译器可以看到你正在运行一个固定次数的循环(或者像4x变量这样的固定倍数),它可以创建非常接近最优的代码。
答案 4 :(得分:1)
来自http://www.sgi.com/tech/stl/Vector.html:
template <class InputIterator>
vector(InputIterator, InputIterator)
Creates a vector with a copy of a range.
答案 5 :(得分:1)
它不使用模板,它不是“完整”展开,但你可以用这样的东西部分展开循环:
void copy (SomeType* a, SomeType* b, int start_index, int num_items) {
int i = start_index;
while (num_items > 4) {
a[i+0] = b[i+0];
a[i+1] = b[i+1];
a[i+2] = b[i+2];
a[i+3] = b[i+3];
i += 4;
num_items -= 4;
}
while (num_items > 0) {
a[i] = b[i];
++i;
--num_items;
}
}
现在在这个特定的例子中,所涉及的额外计算可能会超过仅一次展开四个元素的好处。你应该从顶部循环中越来越多的元素中获得越来越多的好处(在整个函数中,用每个手动展开的迭代中复制的许多元素替换4
)。
答案 6 :(得分:1)
template <int begin, int end> struct copy_;
template <int end> struct copy_<end, end> {
template <typename T> static void execute(T& a, T& b)
{
a[end] = b[end];
}
};
template <int begin, int end> struct copy_<begin, end> {
template <typename T> static void execute(T& a, T& b)
{
a[begin] = b[begin];
copy_<begin+1, end>::execute(a, b);
}
};
template <int begin, int how_many> struct copy {
template <typename T> static void execute(T& a, T& b)
{
copy_<begin, begin+how_many-1>::execute(a, b);
}
};
copy<2, 3>::execute(a, b);
答案 7 :(得分:1)
使用元编程的循环展开可用于创建constexpr(我没有测量时间)。我有一个例子,它可以用来使函数组合(n,k)成为cosntexpr:
template <size_t N> struct iterate_forward {
template <class operation> static auto eval(const operation & op)
{
iterate_forward<N-1>::eval(op);
return op(N-1);
}
};
template <> struct iterate_forward<1>
{
template <class operation> static auto eval(const operation & op)
{ return op(0); }
};
template <> struct iterate_forward<0>
{
template <class operation> static auto eval(const operation & op) {}
};
template <size_t N, size_t K> constexpr size_t COMB()
{
struct ratio
{
size_t operator () (size_t i) const { return (res *= (N-i) / (i+1)); }
mutable size_t res = 1;
};
return iterate_forward<K>::eval(ratio());
}
答案 8 :(得分:0)
#define tl template
#define tn typename
#define st struct
#define cl class
#define us using
template<tn A> st Typ { using type = A; };
tl<tn T> using GetT = tn T::type;
tl<tn F, tn ...As> us apply = tn F::tl apply<As...>;
tl<tn, tn, tn ...> st LoopElements;
tl<tn, tn> st Loop;
tl<tn, tn, tn> st VLoop_i;
tl<tn Sq, tn MF> us VLoop = VLoop_i<GetT<Sq>, Sq, MF>;
//
// TY
//
template<tn T> struct Ty {
template<T ...> struct Pack : Typ<T> {};
tl<tn ...> st Concat_i; tl<tn ...P> us Concat = GetT<Concat_i<P...>>;
tl<T, int64_t> st Seq_i; tl<T f, T t> us Seq = GetT<Seq_i<f, ((int64_t)(t - f))>>; tl<int64_t, tn> st add;
template<tl<T ...> tn C, T ...vs, tl<T ...> tn D, T ...ws, tn ...R> st Concat_i<C<vs...>, D<ws...>, R...> : Typ<Concat<C<vs..., ws...>, R...> >{};
template<tl<T ...> tn C, T ...vs> st Concat_i<C<vs...>> : Typ<C<vs...> >{};
template<int64_t x, T ...vs> struct add<x, Pack<vs...>> : Typ<Pack<((T)(vs + x))...>> {};
template<T f, int64_t c> class Seq_i {
using A = tn Seq_i<f, c/2>::type;
using B = tn add<c/2, A>::type;
using C = tn Seq_i<f + c / 2 * 2, c & 1>::type;
public:
using type = Concat<A, B, C>;
};
tl<T f> st Seq_i<f, 0> : Typ<Pack<>> {};
tl<T f> st Seq_i<f, 1> : Typ<Pack<f>> {};
tl<T f> st Seq_i<f, -1> : Typ<Pack<f>> {};
};
//
// LOOP
template<size_t i, tn F, tn T> struct LoopElement { LoopElement() { apply<F, T>(); }; };
template<size_t ...is, tn F, tn ...P> struct LoopElements<Ty<size_t>::Pack<is...>, F, P...> : LoopElement<is, F, P>... {};
template<tn F, tl<tn ...> cl C, tn ...P> struct Loop<F, C<P...>> : LoopElements<Ty<size_t>::Seq<0, sizeof...(P)>, F, P...> {};
template<tn T, tl<T ...> cl ST, T ...vs, tn MF> struct VLoop_i<T, ST<vs...>, MF> : LoopElements<Ty<size_t>::Seq<0, sizeof...(vs)>, MF, Val<T, vs>...> {};