使用int作为直到运行时才知道的模板参数 [英] Using an int as a template parameter that is not known until run-time

查看:79
本文介绍了使用int作为直到运行时才知道的模板参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to use an integer as a template parameter for a class. Here is a sample of the code:

template< int array_qty > 
class sample_class {

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

}

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

If I do so something like this, it works:

sample_class< 10 > sample_class_instance;

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

However, let's say that I do not know the value of array_qty (the template parameter) when compiling, and will only know it during run-time. In this case, I would essentially be passing an int variable as the template argument. For the sake of demonstration, the following code does not work:

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;

在尝试上述操作时,在编译期间出现以下错误:

I get the following error during compile time when trying the above:

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

$ b $中不可用b

我曾尝试将test_array_qty转换为const,同时将其作为模板参数传递,但这似乎也不起作用。有什么方法可以做到,还是我滥用模板参数?

I've tried converting test_array_qty to a const while passing it as the template parameter, but that doesn't seem to do the trick either. Is there any way to do this, or am I misusing template parameters? Perhaps they need to be known at compile time?

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

The goal is NOT to solve this specific approach, but rather to find a way to set the length of the array to an int variable that can be stated when instantiating the class. If there is a way to do this via a template parameter, that would be ideal.

请注意,我必须为此使用数组,而不要使用向量我可能最终会得到建议。另外,array_qty的值始终在0到50之间-以防产生差异。

Please note that I have to use an array for this, and NOT a vector which I may end up as a suggestion. Additionally, array_qty will always be a value between 0 and 50 - in case that makes a difference.

推荐答案

影响。但是,当我说您问错问题时,请相信我。因此,以下内容回答了您的问题,甚至认为这样做几乎总是一个坏主意。

This can be done in effect. But trust me when I say you are asking the wrong question. So what follows answers your question, even thought doing it is a bad idea almost always.

您实际上可以做的是创建50个不同的程序,每个程序一个50种可能的大小,然后有条件地跳到您想要的大小。

What you in effect can do is create 50 different programs, one for each of the 50 possible sizes, and then conditionally jump to the one you want.

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); ,并且如果value是0到50,则调用 prog< value> :: run()。在 prog :: run 中,模板参数是一个编译时间值。

Call switcher<50>::run( value ); and if value is 0 to 50, prog<value>::run() is invoked. Within prog::run the template parameter is a compile time value.

Horrid hack,很有可能最好使用其他解决方案,但这正是您要的。

Horrid hack, and odds are you would be better off using another solution, but it is what you asked for.

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

Here is a C++14 table-based version:

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

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

某些C ++ 14编译器将阻塞包含lambda的variardic pack扩展。并不是必须的,您可以执行解决方法,但是解决方法很丑。

Some C++14 compilers will choke on the variardic pack expansion containing a lambda. It isn't essential, you can do a workaround, but the workaround is ugly.

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

The C++14 features are all optional: you can implement it all in C++11, but again, ugly.

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

The f passed basically should be a function object (either a lambda taking auto as the first argument, or a manual one). Passing a function name directly won't work well, because the above best works when the first argument becomes a compile-time value.

您可以使用lambda或要帮助的函数对象。

You can wrap a function template with a lambda or a function object to help.

这篇关于使用int作为直到运行时才知道的模板参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆