C++ 将变量作为模板参数传递
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11081573/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passing a variable as a template argument
提问by gibraltar
I am working with a library which exposes an interface to work with. One of the functions of this library is like this :
我正在使用一个公开接口的库。这个库的功能之一是这样的:
template <int a>
void modify(){}
I have to modify parameters from 1 to 10 i.e. call modify
with with template arguments from 1 to 10. For that I wrote this code (a basic version of code, actual code is much larger).
我必须将参数从 1 修改为 10,即modify
使用从 1 到 10 的模板参数调用。为此,我编写了这段代码(代码的基本版本,实际代码要大得多)。
for(int i=0; i<10; i++){
modify<i>();
}
On compilation I receive the following error
在编译时,我收到以下错误
error: 'i' cannot appear in constant-expression
After going through some links on the internet, I came to know that I cannot pass any value as template argument which is not evaluated at compile time.
My question are as follows:
1. Why can't compiler evaluate i
at compile time?
2. Is there any other to achieve the objective I am trying to achieve without changing the API interface?
通过互联网上的一些链接后,我开始知道我不能将任何值作为模板参数传递,这在编译时未评估。我的问题如下: 1. 为什么编译器不能i
在编译时求值?2. 有没有其他方法可以在不改变 API 接口的情况下实现我想要实现的目标?
There is another thing I want to do. Call modify as modify where VAR is the output of some functional computation. How can I do that?
还有一件事我想做。调用 modify 作为修改,其中 VAR 是某些功能计算的输出。我怎样才能做到这一点?
回答by Emilio Garavaglia
What is the value of i(that is not a constant) at compile time? There is no way to answer unless executing the loop. But executing is not "compiling" Since there is no answer, the compiler cannot do that.
编译时i的值(不是常数)是多少?除非执行循环,否则无法回答。但是执行不是“编译”,因为没有答案,编译器不能这样做。
Templates are not algorithm to be executed, but macros to be expanded to produce code. What you can do is rely on specialization to implement iteration by recursion, like here:
模板不是要执行的算法,而是要扩展以生成代码的宏。您可以做的是依靠专业化通过递归实现迭代,如下所示:
#include <iostream>
template<int i>
void modify()
{ std::cout << "modify<"<<i<<">"<< std::endl; }
template<int x, int to>
struct static_for
{
void operator()()
{ modify<x>(); static_for<x+1,to>()(); }
};
template<int to>
struct static_for<to,to>
{
void operator()()
{}
};
int main()
{
static_for<0,10>()();
}
Note that, by doing this, you are, in fact, instantiating 10 functions named
modify<0>
... modify<9>
, called respectively by static_for<0,10>::operator()
... static_for<9,10>::operator()
.
请注意,通过这样做,您实际上是在实例化名为modify<0>
... 的10 个函数
modify<9>
,分别由static_for<0,10>::operator()
...调用static_for<9,10>::operator()
。
The iteration ends because static_for<10,10>
will be instantiated from the specialization that takes two identical values, that does nothing.
迭代结束,因为static_for<10,10>
将从采用两个相同值的特化实例化,什么都不做。
回答by Luc Touraille
Since you asked for an answer using Boost.MPL:
由于您使用Boost.MPL要求答案:
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <iostream>
template <int N>
void modify()
{
std::cout << N << '\n';
}
// You need to wrap your function template in a non-template functor
struct modify_t
{
template <typename N>
void operator()(N)
{
modify<N::value>();
}
};
int main()
{
namespace mpl = boost::mpl;
mpl::for_each< mpl::range_c<int,0,10> >( modify_t() ); // prints 0 to 9
}
回答by Jan Hudec
"Why can't compiler evaluate
i
at compile time?"That would defeat the purpose of templates. Templates are there for the case where the source code looks the same for some set of cases, but the instructions the compiler needs to generate are different each time.
"Is there any other to achieve the objective I am trying to achieve without changing the API interface?"
Yes, look at Boost.MPL.
However I suspect the right answer here is that you want to change the API. It depends on the internals of the
modify
function. I know you have it's source, because templates must be defined in headers. So have a look why it needs to knowi
at compile time and if it does not, it would be best to replace (or complement if you need to maintain backward compatibility) it with normal function with parameter.
“为什么编译器不能
i
在编译时评估?”这将违背模板的目的。模板用于某些情况下的源代码看起来相同的情况,但编译器需要生成的指令每次都不同。
“有没有其他方法可以在不更改 API 接口的情况下实现我想要实现的目标?”
是的,看看Boost.MPL。
但是我怀疑这里的正确答案是您想要更改 API。这取决于
modify
函数的内部结构。我知道你有它的来源,因为模板必须在标题中定义。所以看看为什么它需要i
在编译时知道,如果不需要,最好用带参数的普通函数替换(或补充,如果你需要保持向后兼容性)它。
回答by pPanda_beta
Without using structor Boostit can also be done :
不使用struct或Boost也可以做到:
#include <iostream>
#include <utility>
template <int a>
void modify()
{
std::cout<<a<<",";
}
template<int i,size_t... t>
constexpr inline void CT_for_impl(std::integer_sequence<size_t,t...>)
{
bool kai[]= { (modify<i+t>(), false)...};
}
template<int i,int n>
constexpr inline void CT_for()
{
CT_for_impl<i>(std::make_index_sequence<n-i+1>());
}
int main()
{
CT_for<-5,5>();
return 0;
}
回答by Simranjeet Singh
solution to error: 'i' cannot appear in constant-expression for the above problem
错误的解决方法:'i'不能出现在上述问题的常量表达式中
To read about constexpr click this link
#include <iostream>
using namespace std;
template <typename T>
void modify(T a)
{
cout<<a<<endl; //to check if its working
}
//func converts int a into const int a
constexpr int func(int a)
{
return a;
}
int main(){
for(int i=0; i<10; i++){
modify(func(i));//here passing func(i) returned value which can be used as template argument now as it is converted to constexpr
}
return 0;
}
回答by davidhigh
Given you want to call the functions at run-time by their index and you can't change the API, you can consider type-erasure:
鉴于您想在运行时通过索引调用函数并且您无法更改 API,您可以考虑类型擦除:
std::vector<std::function<void(int)> > func;
func.push_back(modify<1>);
func.push_back(modify<2>);
//... and so on ...
func.push_back(modify<10>);
for(int i=0; i<10; ++i)
{
func[i](); //calls modify<i+1>();
}
Some points to mention:
需要提及的几点:
- That's not what templates are primarily for, but it's a way to bring a static library to the run-time world. The basic requirement for this is that one works with homogeneous types (--if
modify<7>()
would return, say, astd::string
the whole approach would break). - The previous solution using type-erasure has an overhead. One can maybe get it faster by using function pointers, but still it will always be slower than calling the functions at compile time.
- One can (and should) also wrap the
push_back
s into another iterative static function to avoid the manual calls.
- 这不是模板的主要用途,但它是将静态库带入运行时世界的一种方式。对此的基本要求是使用同构类型(--if
modify<7>()
会返回,例如,std::string
整个方法会中断)。 - 以前使用类型擦除的解决方案有开销。可以通过使用函数指针更快地获得它,但它仍然总是比在编译时调用函数慢。
- 还可以(并且应该)将
push_back
s包装到另一个迭代静态函数中以避免手动调用。