【问题标题】:Is there a way to give dynamically values to to a templated function in C++?有没有办法给 C++ 中的模板化函数动态赋值?
【发布时间】:2016-08-05 16:58:21
【问题描述】:

模板元编程的“你好,世界”可以被认为是阶乘代码:

template <unsigned int n>
struct factorial {
    enum { value = n * factorial<n - 1>::value };
};

template <>
struct factorial<0> {
    enum { value = 1 };
};

所以我们可以通过做得到阶乘

cout << factorial<4>::value << endl; //It will print 24

但如果我这样做:

int N = 4;
cout << factorial<N>::value << endl; //COMPILE ERROR

有没有办法给 C++ 中的模板函数动态赋值?

【问题讨论】:

  • 您可以应用一些技巧。 See this post for detailsThis Youtube video 还描述了一个更好的解决方案,尽管是针对不同的问题。
  • 另外:由于没有充分解释的原因,很多人对这篇文章投了反对票。这个问题似乎是合法的。
  • @Xirema:如果你想在编译时评估模板,基于运行时给出的值,你需要一台时间机器。如果这不是很清楚,您不应该坐在电脑前。
  • @IInspectable 我建议您查看我提供的链接,因为您会发现这不是他们在做什么。它们只是在运行时提供对值的 O(1) 访问。
  • @Xirema:使用 O(1) 检索具有线性复杂度的函数的结果是必需的,该值无法在运行时计算。

标签: c++ templates metaprogramming template-meta-programming


【解决方案1】:

不,你不能那样做。模板元编程的重点是在编译时进行一些计算。您的阶乘示例的整个递归扩展链由编译器完成,因此它必须知道 n 的值才能完成计算。

当您直到运行时才知道n 的值时,“常规”编程风格适用,因此调用factorial&lt;N&gt;::value 变得不必要。

【讨论】:

    【解决方案2】:

    你能做到的最好的是:

    constexpr int N = 4;
    std::cout << factorial<N>::value << std::endl;
    

    但是您将无法在运行时修改 N,所以我想这仅是一个小例子。

    【讨论】:

      【解决方案3】:

      这可能对你有用。

      #include<iostream>
      #include<array>
      #include<utility>
      
      //Only >=c++14 supports doubles in constexpr, so we're sticking to integers.
      template<unsigned int I>
      struct FAC {
          static constexpr uint64_t val = I * FAC<I-1>::val;
      };
      
      template<>
      struct FAC<0> {
          static constexpr uint64_t val = 0;
      };
      
      template<>
      struct FAC<1> {
          static constexpr uint64_t val = 1;
      };
      
      template<size_t ... I>
      uint64_t factorial_impl(std::index_sequence<I...>, const unsigned int i) {
          constexpr std::array<uint64_t, sizeof...(I)> a = {FAC<I>::val...};
      
          return a[i];
      }
      
      uint64_t factorial(const unsigned int i) {
          return factorial_impl(std::make_index_sequence<22>(), i); //Can't store factorial values above index 22 without using floating-point values
      }
      
      int main() {
          std::cout << "Which factorial do you want? [1-22]: ";
          unsigned int index = 0;
          std::cin >> index;
          std::cout << "Value of " << index << " is " << factorial(index) << std::endl;
          return 0;
      }
      

      如果您希望它使用双精度,您将需要一个兼容 c++14 的编译器,但这个轻微的修改应该可以工作:

      #include <iostream>
      #include<array>
      #include<utility>
      
      template<unsigned int I>
      struct FAC {
          static constexpr double val = I * FAC<I-1>::val;
      };
      
      template<>
      struct FAC<0> {
          static constexpr double val = 0;
      };
      
      template<>
      struct FAC<1> {
          static constexpr double val = 1;
      };
      
      template<size_t ... I>
      double factorial_impl(std::index_sequence<I...>, const unsigned int i) {
          constexpr std::array<double, sizeof...(I)> a = {FAC<I>::val...};
      
          return a[i];
      }
      
      double factorial(const unsigned int i) {
          return factorial_impl(std::make_index_sequence<170>(), i); //Values above 170 are infinite.
      }
      
      int main() {
          std::cout << "Which factorial do you want? [1-170]: ";
          unsigned int index = 0;
          std::cin >> index;
          std::cout << "Value of " << index << " is " << factorial(index) << std::endl;
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-15
        相关资源
        最近更新 更多