我问How do I capture the results of a recursive function at compile-time?,但我认为我的做法是错误的。
我有一个类似的程序:
#include <iostream>
#include <list>
std::list<unsigned int> recursive_case(std::list<unsigned int>& result, unsigned int& i) {
result.push_front(1 + (i % 10));
i /= 10;
return i != 0 ? recursive_case(result, i) : result;
}
std::list<unsigned int> initial_case(unsigned int i) {
std::list<unsigned int> result;
result.push_back(i % 10);
i /= 10;
return i != 0 ? recursive_case(result, i) : result;
}
int main() {
auto list = initial_case(123);
bool first = true;
for (auto i: list) {
if (first) {
first = false;
} else {
std::cout << ", ";
}
std::cout << i;
}
std::cout << std::endl;
}
输出为2, 3, 3
。
我想执行上述计算并获得相同的输出,但是在编译时(循环迭代和输出打印将在运行时,即从for循环开始的所有内容)。模板看起来像是一种可能性(这就是为什么我这样标记这个问题),但我对在编译时完成工作的任何事情持开放态度。
答案 0 :(得分:2)
您可以使用constexpr
在编译时计算列表。我将递归转换为迭代,并根据需要使用https://pypi.python.org/pypi/psutil来调用calculate
。
#include <iostream>
#include <array>
#include <iterator>
#include <utility>
constexpr std::size_t count_digits(std::size_t N, std::size_t Count = 0)
{
return (N > 0) ? count_digits(N/10, Count+1) : Count;
}
constexpr std::size_t ipow(std::size_t N, std::size_t Base)
{
return (N > 0) ? Base*ipow(N-1,Base) : 1;
}
constexpr std::size_t calculate(std::size_t n, std::size_t i)
{
std::size_t p = ipow(i,10);
std::size_t t = (n/p) % 10;
return i > 0 ? (t+1) : t;
}
template<std::size_t Num, std::size_t C, std::size_t... Is>
constexpr std::array<std::size_t, C> build_list(std::index_sequence<Is...>)
{
return {{ calculate(Num, C-Is-1)... }};
}
template <std::size_t Num, std::size_t C = count_digits(Num)>
constexpr auto build_list()
{
return build_list<Num, C>(std::make_index_sequence<C>{});
}
int main()
{
constexpr auto list = build_list<123>();
for(auto e : list)
{
std::cout << e << " ";
}
return 0;
}
<强>输出:强>
2 3 3
答案 1 :(得分:1)
这是一个解决方案。
#include <iostream>
// Print one digit.
template <unsigned int N, bool Initial> struct AtomicPrinter
{
static void print()
{
std::cout << N%10;
}
};
template <unsigned int N> struct AtomicPrinter<N, false>
{
static void print()
{
std::cout << 1 + N%10 << ", ";
}
};
// Recursive printer for a number
template <unsigned int N, bool Initial> struct Printer
{
static void print()
{
Printer<N/10, false>::print();
AtomicPrinter<N, Initial>::print();
}
};
// Specialization to end recursion.
template <bool TF> struct Printer<0, TF>
{
static void print()
{
}
};
void printList()
{
Printer<123, true>::print();
std::cout << std::endl;
}
int main() {
printList();
}
如果需要将数字的打印与构建数字列表分开,可以使用:
#include <iostream>
#include <list>
template <unsigned int N, bool Initial> struct Digit
{
static void get(std::list<int>& l)
{
l.push_back(N%10);
}
};
template <unsigned int N> struct Digit<N, false>
{
static void get(std::list<int>& l)
{
l.push_back(1 + N%10);
}
};
template <unsigned int N, bool Initial> struct Digits
{
static void get(std::list<int>& l)
{
Digits<N/10, false>::get(l);
Digit<N, Initial>::get(l);
}
};
template <bool TF> struct Digits<0, TF>
{
static void get(std::list<int>& l)
{
}
};
void printList()
{
std::list<int> l;
Digits<123, true>::get(l);
bool first = true;
for (auto i: l) {
if (first) {
first = false;
} else {
std::cout << ", ";
}
std::cout << i;
}
std::cout << std::endl;
}
int main() {
printList();
}
答案 2 :(得分:1)
您可以使用以下内容在编译时拆分数字:
#include <utility>
#include <iostream>
template <char... Cs>
std::integer_sequence<char, Cs...> operator "" _seq() { return {}; }
template <char...Cs>
void print(std::integer_sequence<char, Cs...>)
{
const char* sep = "";
for (const auto& c : {Cs...}) {
std::cout << sep << c;
sep = ", ";
}
}
int main() {
auto seq = 123_seq;
print(seq);
}