c++ - 使用 int 作为直到运行时才知道的模板参数

标签 c++ templates constexpr

我正在尝试使用整数作为类的模板参数。这是代码示例:

template< int array_qty > 
class sample_class {

    public:
        std::array< std::string, array_qty > sample_array;

}

如果我这样做,它会起作用:

sample_class< 10 > sample_class_instance;

但是,假设我在编译时不知道 array_qty(模板参数)的值,只有在运行时才知道。在这种情况下,我基本上会传递一个 int 变量作为模板参数。为了演示,以下代码不起作用:

int test_var = 2;
int another_test_var = 5;
int test_array_qty = test_var * another_test_var;

sample_class< test_array_qty > sample_class_instance;

在尝试上述操作时,我在编译时遇到以下错误:

the value of ‘test_array_qty’ is not usable in a constant expression

我试过将 test_array_qty 转换为 const,同时将其作为模板参数传递,但这似乎也无济于事。有什么办法可以做到这一点,还是我滥用了模板参数?也许他们需要在编译时知道?

目标不是解决这个特定的方法,而是找到一种方法将数组的长度设置为一个 int 变量,该变量可以在实例化类时声明。如果有一种方法可以通过模板参数来执行此操作,那就太理想了。

请注意,我必须为此使用一个数组,而不是我可能最终建议使用的 vector 。此外,array_qty 将始终是 0 到 50 之间的值 - 以防有所不同。

最佳答案

这实际上是可以做到的。但是当我说你问错问题时请相信我。所以下面的内容回答了你的问题,即使认为这样做几乎总是一个坏主意。

您实际上可以做的是创建 50 个不同的程序,每个程序对应 50 种可能的尺寸,然后有条件地跳转到您想要的那个。

template<int n>
struct prog {
  void run() {
    // ...
  }
};


template<int n>
struct switcher {
  void run(int v) {
    if(v==n)
      prog<n>::run();
    else
      switcher<n-1>::run(v);
  }
};

template<>
struct switcher<-1> {
  void run(int v){
  }
};

调用switcher<50>::run( value );如果值为 0 到 50,prog<value>::run()被调用。内 prog::run模板参数是一个编译时值。

可怕的 hack,使用其他解决方案可能会更好,但这正是您所要求的。

这是一个基于 C++14 表的版本:

template<size_t N>
using index_t = std::integral_constant<size_t, N>; // C++14

template<size_t M>
struct magic_switch_t {
  template<class F, class...Args>
  using R=std::result_of_t<F(index_t<0>, Args...)>;
  template<class F, class...Args>
  R<F, Args...> operator()(F&& f, size_t i, Args&&...args)const{
    if (i >= M)
      throw i; // make a better way to return an error
    return invoke(std::make_index_sequence<M>{}, std::forward<F>(f), i, std::forward<Args>(args)...);
  }
private:
  template<size_t...Is, class F, class...Args>
  R<F, Args...> invoke(std::index_sequence<Is...>, F&&f, size_t i, Args&&...args)const {
    using pF=decltype(std::addressof(f));
    using call_func = R<F, Args...>(*)(pF pf, Args&&...args);
    static const call_func table[M]={
      [](pF pf, Args&&...args)->R<F, Args...>{
        return std::forward<F>(*pf)(index_t<Is>{}, std::forward<Args>(args)...);
      }...
    };
    return table[i](std::addressof(f), std::forward<Args>(args)...);
  }
};

magic_switch_t<N>{}( f, 3, blah1, blah2, etc )将调用 f(index_t<3>{}, blah1, blah2, etc) .

某些 C++14 编译器会因包含 lambda 的可变变量包扩展而窒息。这不是必需的,您可以采取变通办法,但变通办法很丑陋。

C++14 的功能都是可选的:您可以在 C++11 中实现所有功能,但同样很丑陋。

f passed 基本上应该是一个函数对象(以 auto 作为第一个参数的 lambda,或者手动的)。直接传递函数名效果不佳,因为当第一个参数成为编译时值时,上述方法效果最佳。

您可以使用 lambda 或函数对象包装函数模板以提供帮助。

关于c++ - 使用 int 作为直到运行时才知道的模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14417430/

相关文章:

c++ - L ""and u8"之间的区别“

c++ - const char * 和 const char (& p)[T_Size] 之间的最佳查找匹配

c++ - 实例化一个模板类,该模板类在具有不同函数签名的构造函数中采用函数指针

c++ - 模板函数的两个特化(int 和 int*)。编译错误

c++ - 静态大小的 valarray 实现

python - 如何将 BitString 转换为 ctypes 字节数组?

C++删除txt文件中的最后一个字符

c++ - 等效于 C++ 中的 Objective-C 的 "valueForKey"方法?

c++ - std::piecewise_construct 不会导致 ODR 违规吗?

c++ - numeric_limits 是最小/最大常数吗?