我已经尝试过了,并在我第一次发表评论后找到了可能的解决方案。因此,只需将声明包含在泛型函数中,它就可以工作!请参阅下面的示例代码。
最后的一点似乎是 模板化 代码没有在 非模板化 代码中完成elem() 的声明。
它在模板的定义之后,但在它的第一次实例化之前,所以,据我所知/理解,这应该足够了......但我的编译器(gcc 4.8.2)也抱怨。我肯定已经在模板化的方法和类中多次使用过这个特性。
这对我来说似乎真的很奇怪,可能是一个错误(@Potatoswatter:你能给出这个错误的参考 - 看看是否匹配?)。
编辑:终于明白了。还在学习C++11 Stroustrup's!它按标准中的预期工作。我在这里给出一些指示 - 摘录。
第一个重要的想法是在 23.3.2 中提出的(模板,错误检测):在第一次使用定义之前,先检查定义中的语法错误。当然是,但它只是后来才定义的。但是:“模板定义中使用的名称必须在范围内或以某种合理明显的方式取决于模板参数”。这一点现在已经很清楚了,但最重要的是这个想法背后的基本原理。
在 26.3 (Instantiation [of templates!], Name Binding) 中有非常详细的解释:“定义模板函数以最小化对非本地信息的依赖。原因是模板将用于基于未知类型和未知上下文生成函数和类。每个微妙的上下文依赖都可能成为某人的问题......"。
读完之后——我仍然在问自己,为什么我没有想到关于泛型类中存在的受控环境的如此重要的区别!
继续解释(第 745-758 页!),解决机制在 26.3.2(Point-of-definition Binding)和 26.3.3(Point实例化绑定):
“当编译器看到模板定义时,它会确定哪些名称是依赖的(26.3.1)。如果名称是依赖的,则查找其声明将推迟到实例化时间(26.3.3)。”
“不依赖于模板参数的名称被视为不在模板中的名称;它们必须在定义点的范围 (6.3.4) 内”。
那是石头。 elem() 必须在用于模板定义之前声明 - 它被视为不在模板中的名称。
我同意@Potatoswatter 和其他人的观点。这可能是不太优雅的解决方案,因为它仅限于使用外部函数,没有仿函数,没有 lambda。
另一方面,它解决了 OP 的问题(最初认为这是一种解决方法......不,这正是它的预期工作方式!)。
#include <iostream>
using namespace std;
template<typename M, typename R>
void func(M mat, int cols, int rows)
{
// with this declaration it works.
R &elem(M, int, int);
for(int i = 0; i < cols; ++i) {
for(int j = 0; j < rows; ++j) {
elem(mat, i, j) += 1; // +=1 is just your "doSomething()"
}
}
}
template<typename M, typename R>
void show(M mat, int cols, int rows)
{
R &elem(M, int, int);
for(int i = 0; i < cols; ++i) {
for(int j = 0; j < rows; ++j) {
if (j>0) cout << ", ";
cout << elem(mat, i, j);
}
cout << endl;
}
}
float &elem(float *m, int i, int j) {
return m[i*3+j];
}
float &elem(float m[3][3], int i, int j) {
return m[i][j];
}
int main(int argc, char **argv) {
float mat1d[9] = {1,2,3,4,5,6,7,8,9};
float mat2d[3][3] = {1,2,3,4,5,6,7,8,9};
func<float*, float>(mat1d, 3, 3);
show<float*, float>(mat1d, 3, 3);
func<float(*)[3], float>(mat2d, 3, 3);
show<float(*)[3], float>(mat2d, 3, 3);
}
在你的问题中尝试使用引用我有点疯狂,然后才明白将它们与静态声明的大小混合在一起,让事情变得更加卡住。我把它包括在这里是因为我已经浪费了很多时间来解决这个问题:
#include <iostream>
using namespace std;
template<typename M, typename R>
void func(M &mat, int cols, int rows)
{
R &elem(M&, int, int);
for(int i = 0; i < cols; ++i) {
for(int j = 0; j < rows; ++j) {
elem(mat, i, j) += 1; // +=1 is just your "something"
}
}
}
template<typename M, typename R>
void show(M &mat, int cols, int rows)
{
R &elem(M&, int, int);
for(int i = 0; i < cols; ++i) {
for(int j = 0; j < rows; ++j) {
if (j>0) cout << ", ";
cout << elem(mat, i, j);
}
cout << endl;
}
}
float &elem(float (&m)[9], int i, int j) {
return m[i*3+j];
}
float &elem(float (&m)[3][3], int i, int j) {
return m[i][j];
}
int main(int argc, char **argv) {
float mat1d[9] = {1,2,3,4,5,6,7,8,9};
float mat2d[3][3] = {1,2,3,4,5,6,7,8,9};
func<float[9], float>(mat1d, 3, 3);
show<float[9], float>(mat1d, 3, 3);
func<float[3][3], float>(mat2d, 3, 3);
show<float[3][3], float>(mat2d, 3, 3);
}
注意:这样elem() 是一个函数,包含在链接时。我认为这不是您想要的,但是您可以绕过它,制作所有东西的函子。