简体   繁体   English

如何在编译时使用C ++模板存储递归函数的中间结果?

[英]How do I store the intermediate results of a recursive function using C++ templates at compile time?

I asked How do I capture the results of a recursive function at compile-time? 我问我如何在编译时捕获递归函数的结果? , but I think my approach was wrong. ,但我认为我的方法是错误的。

I have a program like so: 我有一个像这样的程序:

#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;
}

The output is 2, 3, 3 . 输出为2, 3, 3

I want to perform the above computation and get the same output but in compile-time (the loop iteration and output-printing would be at runtime ie everything starting from the for loop). 我想执行上述计算并在编译时获得相同的输出(循环迭代和输出打印将在运行时进行,即一切都从for循环开始)。 Templates seem like a possibility (that's why I tagged this ask as such), but I am open to anything that gets the job done in compile-time. 模板似乎是有可能的(这就是为什么我这样标记了这个问号),但是我愿意接受在编译时完成工作的任何事情。

You can use constexpr to calculate the list at compile time. 您可以在编译时使用constexpr来计算列表。 I converted the recursion to iteration and used the indices trick to call calculate as often as necessary. 我将递归转换为迭代,并根据需要使用索引技巧来调用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;
}

output: 输出:

2 3 3 

live example 现场例子

Here's one solution. 这是一个解决方案。

#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();
}

If there is a need to separate printing of the digits from constructing the list of digits, you can use: 如果需要将数字的打印与构造数字的列表分开,则可以使用:

#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();
}

You may use something like the following to split number at compile time: 您可以在编译时使用以下类似的方法拆分数字:

#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);
}

Demo 演示版

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用C ++模板或宏进行编译时函数生成 - Using C++ templates or macros for compile time function generation 使用模板的C ++编译时间检查器 - C++ compile time checker using templates 如何使用 C++ 模板减少编译时间 - How to reduce compile time with C++ templates 如何使我的 function 根据使用 C++ 中的模板调用的类型返回不同的结果 - How do I make my function return different results depending on type it's been called using templates in C++ 在函数堆栈中使用C ++ future作为中间值会导致段错误 - Using a C++ future as an intermediate value in a function stack results in a segfault C ++ /模板:是否可以在编译时有选择地禁用类的功能? - C++/templates: Can I selectively disable a function of a class at compile time? 使用带有参数类型的可变参数模板在c ++中获取函数在编译时的参数个数 - Getting the number of arguments to a function at compile-time using variadic templates with argument type check in c++ 使用C ++中的STXXL模板的递归模板函数出错 - Error in a recursive template function using STXXL templates in C++ 使用模板时的 C++ 构造函数或递归成员函数 - C++ constructor or recursive member function when using templates 使用c ++中的模板编译时断言 - Compile-time assert using templates in c++
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM