是否有通过模板元编程计算连续数字总和的智能方法? 这将是例如1到100的非模板算法。
import csv
import shapefile # pyshp module
def decoder(records):
for record in records:
rec = []
for element in record:
try:
ele = element.decode('utf-8')
rec += [ele]
except: # since str and int have no attribute decode
ele = element # done for consistency
rec += [ele]
yield rec # easy generator
sf = shapefile.Reader('/path/to/a/shapefile')
my_file = '/path/to/a/csv'
records = [record for record in decoder(sf.iterRecords())]
with open(my_file, 'w', encoding='utf-8', newline='') as f:
w = csv.writer(f, delimiter=',')
for rec in records:
w.writerow(rec)
我考虑使用可变参数添加函数并用参数列表填充它。但是我不确定如何创建参数列表。
int i = 0;
for (int n = 1; n <= 100; n++)
i += n;
return i;
答案 0 :(得分:6)
template <int n>
struct SumOfNumbers {
static constexpr int value = n*(n+1)/2;
};
答案 1 :(得分:3)
如果代码置于constexpr
函数内,则可以在编译时执行。
constexpr int sum(int x)
{
int i = 0;
for (int n = 1; n <= x; n++)
i += n;
return i;
}
如果你想在模板中使用它,你可以这样做:
template <int n>
struct sum_t {
static constexpr int value = sum(n);
};
答案 2 :(得分:1)
虽然answer by Igor是解决问题的一个很好的答案,但以下方法更类似于for循环。
template <int n>
struct AddHelper { static const int value = n + AddHelper<n-1>::value; };
template <>
struct AddHelper<0> { static const int value = 0; };
template <int n>
int add() { return AddHelper<n>::value; }
答案 3 :(得分:1)
简单的方法是使用constexpr
。 constexpr
,特别是在C ++ 14中,允许您获取运行时代码并使其编译时间。
在C ++ 11中,你必须通过递归获得愚蠢。幸运的是2017年,即C ++ 14发布后的几年,所以你不必使用C ++ 11。如果您被迫,可以在问题template
中标记constexpr
实施。
然后
template<int...Is>
constexpr int add() { return add(0, Is...); }
如果您只是必须在<>
s内传递参数,就可以了。
有时人们在想要一般解决方案时会问这些问题,而只选择add
只针对特定问题,而不是意识到它包含的问题会使问题变得更容易。
如果失败了,对二进制加法的左或右折叠可以起作用。二进制左或右折叠的缺点是它具有O(n)模板实例化深度和O(n ^ 2)总模板名称长度。这两者都限制了您可以添加的序列的长度,并使其非常慢并且消耗内存。
在C ++ 17中,处理它的方法是使用内置的折叠操作。如果要折叠的二进制操作不是内置的操作,请使用操作符重载和包装类型强制在执行语言内置折叠时调用它。这是C ++ 17,你的问题是C ++ 11,所以我不会详细介绍。
在C ++ 11中,您需要折叠一些任意对称二进制操作,您可以使用对数递归深度获取一个东西并将其分解为二叉树。
这很棘手;基本的想法是编写一个函数,在列表中将列表拆分为两个,然后使用前缀和后缀列表进行处理。
然后,在伪代码中,如果我们有where
个索引,只有在list={L0, Ls...}
被提及时才会L0
(否则它只是一些列表)。
split( where, before, list )
if where=0, answer is before, list
if where=1, answer is before+{L0}, {Ls...}
otherwise, is:
using tmp[2] = split((where+1)/2, before, list)
answer is split( where/2, tmp[0], tmp[1])
诀窍是我们做了很多实例化,但递归深度很短。
一旦我们得到split
,我们就可以获取一个元素列表,构建一个快速平衡的二叉树,并将二元运算符应用于每对元素,并再次以对数深度求解树。
老实说,这比升级编译器更麻烦。
TL; DR:将您的编译器升级到c++14或c++17,这很容易。
如果失败,请尝试并添加constexpr
。现在按原样使用,或转发
template<int...Is>
constexpr int add()
到它。
答案 4 :(得分:1)
我考虑使用可变参数添加函数并用参数列表填充它。但是我不知道如何创建参数列表。
首先,我建议您遵循Igor Tandetnik(+1)的基于高斯的解决方案。
第二:我不知道如何创建参数列表,但如果你接受std::integer_sequence
(所以参数列表固定编译时间),从C ++ 14开始你可以使用{{ 1}}。
在这种情况下,您的std::make_integer_sequence
函数无需递归,如以下示例所示
add()
在C ++ 17中,解决方案更简单
#include <utility>
template <typename T, T ... Is>
constexpr T add (std::integer_sequence<T, Is...> const & a)
{
using unused = int[];
T sum {};
(void)unused { 0, ( sum += Is, 0 )... };
return sum;
}
int main ()
{
constexpr int sum1 { (100 * (100 + 1)) >> 1 }; // Gauss
constexpr int sum2 { add(std::make_integer_sequence<int, 100+1>{}) };
static_assert( sum1 == sum2, "!");
}