2011-03-10 172 views
3

我遇到了非类型(int变量)模板参数的问题。
为什么我不能将一个常量int变量传递给一个函数,并让该函数实例化模板?非类型模板参数

template<int size> 
class MyTemplate 
{ 
    // do something with size 
}; 

void run(const int j) 
{ 
    MyTemplate<j> b; // not fine 
} 
void main() 
{ 
    const int i = 3; 
    MyTemplate<i> a; // fine; 
    run(i); // not fine 
} 

不精:编译说,错误: 'J' 不能出现在常量表达式

  • 编辑

这是我结束了。也许有人可能会使用它,有人可能会建议更好的方法。

enum PRE_SIZE 
{ 
    PRE_SIZE_256 = 256, 
    PRE_SIZE_512 = 512, 
    PRE_SIZE_1024 = 1024, 
}; 

template<int size> 
    class SizedPool : public Singleton< SizedPool<size> > 
{ 
public: 
    SizedPool() 
     : mPool(size) 
    { 
    } 
    void* Malloc() 
    { 
     return mPool.malloc(); 
    } 

    void Free(void* memoryPtr) 
    { 
     mPool.free(memoryPtr); 
    } 

private: 
    boost::pool<>  mPool; 
}; 

template<int size> 
    void* SizedPoolMalloc() 
    { 
     return SizedPool<size>::GetInstance()->Malloc(); 
    } 

template<int size> 
    void SizedPoolFree(void* memoryPtr) 
    { 
     SizedPool<size>::GetInstance()->Free(memoryPtr); 
    } 

void* SizedPoolMalloc(int size) 
{ 
    if (size <= PRE_SIZE_256) 
     return SizedPoolMalloc<PRE_SIZE_256>(); 
    else if (size <= PRE_SIZE_512) 
     return SizedPoolMalloc<PRE_SIZE_512>(); 
} 


void toRun(const int j) 
{ 
    SizedPoolMalloc(j); 
} 
void Test17() 
{ 
    const int i = 3; 
    toRun(i); 
} 
+0

+1一个很好的问题! – Nawaz 2011-03-10 08:04:19

+0

很快,因为在编译时编译器必须知道模板参数。 – 2011-03-10 08:04:52

回答

9

因为非类型模板参数在编译时需要值。请记住,模板是一种编译时机制;最终的可执行文件中不存在模板。还要记住,函数和参数传递给函数是运行时机制。在run()j参数的值只有在程序实际运行并调用run()函数后才能知道,编译阶段之后已过去。

void run(const int j) 
{ 
    // The compiler can't know what j is until the program actually runs! 
    MyTemplate<j> b; 
} 

const int i = 3; 
run(i); 

这就是为什么编译器抱怨说“'j'不能出现在常量表达式中”。

另一方面,这很好,因为i的值在编译时已知。

const int i = 3; 
// The compiler knows i has the value 3 at this point, 
// so we can actually compile this. 
MyTemplate<i> a; 

您可以将编译时值传递给运行时结构,但不能以其他方式传递。

但是,你可以有你run()函数接受一个非类型模板参数您MyTemplate模板类接受一个非类型模板参数以同样的方式:

template<int j> 
void run() 
{ 
    MyTemplate<j> b; 
} 

const int i = 3; 
run<i>(); 
+0

嗯,我认为,因为我是在编译时定义并传递给run(),所以它会是编译时常量。有没有解决这个问题?(因为它似乎是一个常见的要求) – eugene 2011-03-10 07:58:37

+0

@Eugene:记住调用一个函数并将参数传递给一个函数是一种运行时机制。 'run()'的函数体不可能知道'j'实际上是一个编译时常量。如果'run()'是在一个完全不同的源文件中定义的呢?在不同的库或应用程序中? – 2011-03-10 08:02:43

+0

哇我刚刚做了你的建议(虽然在一个虚拟课堂上,不知道我只能在课堂外定义模板功能)。谢谢 – eugene 2011-03-10 08:06:48

1

因为Ĵ应该在编译时是已知的。在你的例子中,它不是。

+1

非常有说服力的回复。 +1 – Nawaz 2011-03-10 08:04:57

2

基本上,C++有两种常量:

const int a = 5; 
MyTemplate<a> foo; // OK 

const int b = rand(); 
MyTemplate<b> foo; // Not OK. 

第一个例子是一个编译时间常数。在C++标准中讲,它是一个积分常量表达式(ICE)。第二个例子是运行时常量。它具有相同的C++类型(const int),但它不是ICE。

您的功能void run(const int j)是运行时常量。你甚至可以通过用户输入。因此它不是有效的模板参数。

规则的原因是编译器必须根据模板参数值生成代码。如果它没有编译时常量,它不能这样做。