使用int作为模板参数,直到运行时才知道

use*_*404 7 c++ templates constexpr

我试图使用整数作为类的模板参数.以下是代码示例:

template< int array_qty > 
class sample_class {

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

}
Run Code Online (Sandbox Code Playgroud)

如果我这样做,它的工作原理:

sample_class< 10 > sample_class_instance;
Run Code Online (Sandbox Code Playgroud)

但是,假设我在编译时不知道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;
Run Code Online (Sandbox Code Playgroud)

在尝试上述过程中,在编译期间出现以下错误:

the value of ‘test_array_qty’ is not usable in a constant expression
Run Code Online (Sandbox Code Playgroud)

我已经尝试将test_array_qty转换为const,同时将其作为模板参数传递,但这似乎也没有.有没有办法做到这一点,还是我滥用模板参数?也许他们需要在编译时知道?

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

请注意,我必须使用一个数组,而不是我最终可能作为建议的向量.此外,array_qty将始终是0到50之间的值 - 如果有所不同.

Yak*_*ont 10

这可以有效地完成.但是当我说你提出错误的问题时,请相信我.接下来回答你的问题,甚至认为这样做几乎总是一个坏主意.

你实际可以做的是创建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){
  }
};
Run Code Online (Sandbox Code Playgroud)

调用switcher<50>::run( value );,如果值为0到50,prog<value>::run()则调用.在prog::runtemplate参数内是编译时间值.

可怕的黑客,你可能会更好地使用另一种解决方案,但这是你要求的.

这是一个基于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...Args>
  using R=std::result_of_t<F(index_t<0>, Args...)>;
  template<class F, class...Args>
  R<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<Args...> invoke(std::index_sequence<Is...>, F&&f, size_t i, Args&&...args)const {
    using pF=decltype(std::addressof(f));
    using call_func = R<Args...>(*)(pF pf, Args&&...args);
    static const call_func table[M]={
      [](pF pf, Args&&...args)->R<Args...>{
        return std::forward<F>(*pf)(index_t<Is>{}, std::forward<Args>(args)...);
      }...
    };
    return table[i](std::addressof(f), std::forward<Args>(args)...);
  }
};
Run Code Online (Sandbox Code Playgroud)

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

一些C++ 14编译器会阻塞包含lambda的variardic pack扩展.这不是必需的,你可以做一个解决方法,但解决方法是丑陋的.

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

所述f基本上传递应该是一个功能对象(无论是一个lambda以auto作为第一个参数,或手动的).直接传递函数名称将无法正常工作,因为当第一个参数成为编译时值时,上述效果最佳.

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


Jer*_*fin 5

对于C++ 11,非类型模板参数仅限于以下内容(§14.3.2/ 1):

非类型非模板模板参数的模板参数应为以下之一:

  • 对于整数或枚举类型的非类型模板参数,模板参数类型的转换常量表达式(5.19); 要么
  • 非类型模板参数的名称; 要么
  • 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址,或具有外部或内部链接的函数,包括函数模板和函数模板-id,但不包括非静态类成员,表示(忽略)括号)as&id-expression,除非如果名称引用函数或数组,可以省略&,如果相应的template-parameter是引用,则省略; 要么
  • 一个常量表达式,其值为空指针值(4.10); 要么
  • 一个常量表达式,其值为null成员指针值(4.11); 要么
  • 指向成员的指针,如5.3.1中所述.

在C++ 98和03中,列表更受限制.一句话:你不想做什么.