c++模板规范和重载的解析

发布于 2024-11-14 14:02:33 字数 954 浏览 2 评论 0原文

我已经阅读了 为什么不专门化函数模板,并在进行了一些实验之后, 我发现了一件有趣的事情。这里是 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ヤ经典坏疍 2024-11-21 14:02:33

将源代码分发到三个文件只会让问题变得混乱:预处理会生成一个编译单元,而行为仅取决于 CU 的内容,而不取决于分发的文件数量。

我认为您会对在这种情况下

#include <iostream>

template<class T> void foo(T); // A
template<> void foo(int*); // 1
template<class T> void foo(T*); // B

template<class T> void foo(T x)
{ std::cout << "T version." << std::endl; }

template<> void foo(int *i) // 2
{ 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* 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) 的定义,你必须这样写

template <> void foo<int*>(int*) // definition for (1)
{ std::cout << "foo<int*>(int*)\n"; }

You might also be Explicit when Define (2):

template<> void foo<int>(int *i) // 2 alternate
{ std::cout << "int* version." << std::endl; }

(但显然给出 (2) 和这个替代版本在同一个CU 会给你一个错误)。

调用函数时也可以明确:

foo(p); // call (2)
foo<int>(p); // call (2)
foo<int*>(p); // call (1)

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

#include <iostream>

template<class T> void foo(T); // A
template<> void foo(int*); // 1
template<class T> void foo(T*); // B

template<class T> void foo(T x)
{ std::cout << "T version." << std::endl; }

template<> void foo(int *i) // 2
{ 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);
}

you get int* version. This is the expected behavior. While (1) does declare a specialization of template <typename T> void foo(T), (2) isn't the definition of that specialization. (2) defines and declares a specialization of template<class T> void foo(T*); which is then called in main(). 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 declaration template<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

template <> void foo<int*>(int*) // definition for (1)
{ std::cout << "foo<int*>(int*)\n"; }

You could also be explicit when defining (2):

template<> void foo<int>(int *i) // 2 alternate
{ std::cout << "int* version." << std::endl; }

(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:

foo(p); // call (2)
foo<int>(p); // call (2)
foo<int*>(p); // call (1)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文