c++模板规范和重载的解析
我已经阅读了 为什么不专门化函数模板,并在进行了一些实验之后, 我发现了一件有趣的事情。这里是 main.cxx:
// main.cxx
#include <iostream>
// Declarations
/*
template<class T>
void foo(T);
template<>
void foo(int*);
template<class T>
void foo(T*);
*/
// Definition and specification
template<class T>
void foo(T x)
{
std::cout << "T version." << std::endl;
}
template<>
void foo(int *i)
{
std::cout << "int* version." << std::endl;
}
template<class T>
void foo(T *x)
{
std::cout << "T* version" << std::endl;
}
int main(int argc, char** argv)
{
int *p;
foo(p);
}
有趣的是:如果我对声明部分进行注释,则行为正如文章所述,即如果 int* 版本的定义在其定义之前,则将使用 T* 版本,反之亦然。但是,如果取消注释声明块,则无论我在定义或声明中使用哪种顺序,都只会调用 int* 版本。我的问题是这个声明如何影响决议?
有什么想法吗?我在 x86_64-redhat-linux 上使用 g++ 4.2.2
编辑:看到 AProgrammer 的答案后简化这个问题
I've read the Why Not Specialize Function Templates and after experiment a little bit,
I found an interesting thing. Here go the main.cxx:
// main.cxx
#include <iostream>
// Declarations
/*
template<class T>
void foo(T);
template<>
void foo(int*);
template<class T>
void foo(T*);
*/
// Definition and specification
template<class T>
void foo(T x)
{
std::cout << "T version." << std::endl;
}
template<>
void foo(int *i)
{
std::cout << "int* version." << std::endl;
}
template<class T>
void foo(T *x)
{
std::cout << "T* version" << std::endl;
}
int main(int argc, char** argv)
{
int *p;
foo(p);
}
the interesting thing is: if I leave the declaration part commented, the behaviors are just as the article said, i.e. T* version will be used if definition of int* version goes before its definition and vice and verse. However, if uncomment the declaration block, only int* version will be called no matter which order I use in definitions or declarations. My question is how this declaration come to affect the resolution?
Any ideas? I use g++ 4.2.2 on x86_64-redhat-linux
EDIT: simplify this question after saw AProgrammer's answer
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
将源代码分发到三个文件只会让问题变得混乱:预处理会生成一个编译单元,而行为仅取决于 CU 的内容,而不取决于分发的文件数量。
我认为您会对在这种情况下
获得
int* version
感到惊讶。这是预期的行为。而 (1) 确实声明了template的特化; void foo(T), (2) 不是该专业化的定义。 (2) 定义并声明
template的特化; void foo(T*);
然后在main()
中调用。如果您在放置声明和定义时在三个定义之前给出三个声明,就会发生这种情况。定义 (2) 总是会看到声明template。 void foo(T*);
从而成为它的特化。当声明或定义函数模板的特化并且它可以是多个函数模板的特化时(例如这里(2)可以是两个重载 A 和 B 的特化,它们只需要声明),它是专业化是“更专业”之一。您可以在标准第 17.5.5.2 节中看到“更专门化”的精确定义,但是很容易看出 B 比 A 更匹配 (2),因此 (2) 是 (B) 的特化。 (1) 声明了 (A) 的特化,因为声明 (1) 时,还没有看到 (B)。如果你想在看到 (B) 后给出 (1) 的定义,你必须这样写
You might also be Explicit when Define (2):
(但显然给出 (2) 和这个替代版本在同一个CU 会给你一个错误)。
调用函数时也可以明确:
Distributing the source into three files just confuse the matter: the preprocessing makes one compilation unit and the behavior just depend on the content of the CU and not in how many files it was distributed.
I think that you are surprised that in this case
you get
int* version
. This is the expected behavior. While (1) does declare a specialization oftemplate <typename T> void foo(T)
, (2) isn't the definition of that specialization. (2) defines and declares a specialization oftemplate<class T> void foo(T*);
which is then called inmain()
. This will happen if you gives the three declarations before the three definitions in whatever you put the declarations and definitions. The definition (2) will always see the declarationtemplate<class T> void foo(T*);
and thus be a specialization of it.When a specialization for a function template is declared or defined and it could be a specialization for several function templates (like here (2) can be a specialization of the two overloads A and B, they just need to be declared), it it a specialization of the "more specialized" one. You can see the precise definition of "more specialized" in the standard section 17.5.5.2, but it is quite easy to see that B is a better match than A for (2) and thus (2) is a specialization of (B). (1) declares a specialization of (A) because when (1) is declared, (B) hasn't been seen yet. If you wanted to give the definition of (1) after (B) has been seen, you'd have to write
You could also be explicit when defining (2):
(but obviously giving (2) and this alternate version in the same CU will gives you an error).
You can be also explicit also when calling the functions: