当前位置: 首页 > 知识库问答 >
问题:

模板函数重载与相同的签名,为什么这项工作?

蒋华美
2023-03-14

最小程序:

#include <stdio.h>

#include <type_traits>

template<typename S, typename T>
int foo(typename T::type s) {
    return 1;
}

template<typename S, typename T>
int foo(S s) {
    return 2;
}

int main(int argc, char* argv[]) {
    int x = 3;
    printf("%d\n", foo<int, std::enable_if<true, int>>(x));

    return 0;
}

输出:

    1 

为什么这不会导致编译错误?生成模板代码时,函数intfoo(typename t::type search)intfoo(S)会不会

如果您稍微更改一下模板函数签名,它仍然可以工作(正如我在上面的示例中所期望的那样):

template<typename S, typename T>
void foo(typename T::type s) {
    printf("a\n");
}

template<typename S, typename T>
void foo(S s) {
    printf("b\n");
}

但这并没有,唯一的区别是一个有int签名,另一个由第一个模板参数定义。

template<typename S, typename T>
void foo(typename T::type s) {
    printf("a\n");
}

template<typename S, typename T>
void foo(int s) {
    printf("b\n");
}

编译器错误(叮当声):

test.cpp:26:2: error: call to 'foo' is ambiguous
foo<std::enable_if<true, int>>(3);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:16:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(typename T::type s) {
        ^
test.cpp:21:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(int s) {
        ^
1 error generated.

我在一个项目中使用了类似的代码,我担心在某些情况下,语言中有一个微妙的、我不理解的地方会导致一些未定义的行为。我还应该提到,它在Clang和VS11上都可以编译,所以我不认为这只是一个编译器错误。

编辑:更正第二个案例(打字错误);添加了来自Clang的错误消息。

编辑#2:对于那些询问T::类型是什么意思的人。

从…起http://en.cppreference.com/w/cpp/types/enable_if:

样板

如果B为true,则std::enable_如果有公共成员typedef type,则等于T;否则,就没有成员typedef。

如果是结构,则启用_。基本上,如果enable_if的第一个模板参数中计算的表达式为true(在我上面的例子中为true),那么将有一个公共成员type,其类型与第二个模板参数相同。

的情况下,如果


共有2个答案

濮阳振
2023-03-14

这是对这一现象的进一步简化:

#include <stdio.h>

template<typename T>
void foo(int arg) {
    printf("a\n");
}

template<typename T>
void foo(T arg) {
    printf("b\n");
}

int main(int argc, char* argv[]) {
    foo<int>(3);   // prints "a"
    foo(3);        // prints "b"

    return 0;
}

模板参数可以通过尖括号显式传递,也可以通过演绎法解析。如果未明确指定参数,则必须使用函数的参数来推断该参数。

因此,在foo(3)的情况下,模板“a”将不起作用,因为参数t没有明确指定,也无法推导。在foo的情况下

http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/partial_ordering_funct_templ.htm

我现在看到其他人已经回答了(我不擅长快速回答问题),所以我现在就总结一下,说模板“a”更专业,就像沃恩说的那样。

顾均
2023-03-14

第一个函数被认为比第一个函数更专业。

功能

int foo(typename T::type)

可以匹配

template <typename S,typename T> int foo(S s)

通过使用T::type作为参数S的值

int foo(S s)

不匹配

template <typename S,typename T> int foo(typename T::type)

因为T无法推导。

逻辑在第14.5.5.2节的C 03标准和第14.5.6.2节的C 11标准中进行了布局。

这个想法是:为了查看一个函数是否比另一个函数更专业,可以为第一个函数的每个模板参数创建值,然后查看第二个函数是否可以匹配结果签名。还可以为第二个函数的模板参数创建值,并查看第一个函数是否与生成的签名匹配。如果第二个函数可以匹配第一个函数,那么第二个函数就不能比第一个函数更专业。除此之外,如果第一个函数与第二个函数不匹配,那么第一个函数必须比第二个函数更专业。这就是你的情况。

 类似资料:
  • 模板函数与重载是密切相关的。从函数模板产生的相关函数都是同名的,因此编译器用重载的解决方法调用相应函数。 函数模板本身可以用多种方式重载。我们可以提供其他函数模板,指定不同参数的相同函数名。例如,图12.2的printArray函数模板可以用另一printArray函数模板重载,用参数lowSubscriPt和highSubscript指定要打印的数组部分(见练习12.4)。 函数模板也可以用其他

  • 我正在学习一个视频教程,我想声明一个模板函数作为模板类的朋友。我不知道为什么代码会抛出错误。 编译器抛出错误。 错误: templates\u friends\u 38。cpp:在“void doSomething2(T)[T=int]”的实例化中:templates\u friends\u 38。cpp:40:19:此处需要templates\u friends\u 38。cpp:32:9:错误

  • 这是在参数是重载函数时重载解析如何工作中提到的更复杂的问题? 下面的代码编译起来没有任何问题: 模板参数推导似乎不是一项具有挑战性的任务-只有一个函数接受两个参数。但是,取消注释的模板重载(仍然只有一个参数)会无缘无故地破坏编译。gcc 5. x/6. x和clang 3.9的编译都失败了。 它可以用重载解析/模板参数推导规则来解释,还是应该在这些编译器中被限定为缺陷?

  • 让我们考虑以下代码: 我知道第二个声明是重载,而不是部分专业化: 但我想知道它与部分专业化有何不同?它为我们提供了与部分专业化相同的功能,不是吗?

  • 刚接触XML并尝试使用XML实验室(https://github.com/harshitha-akkaraju/layoutlab) 让我困惑的是,即使按钮的宽度是0dp,但如果宽度是wrap_content的话,它也是。我知道0dp相当于ConstraintLayout中的“match_constraint”。然而,那不是意味着0dp应该填满尽可能多的空间吗?

  • 问题内容: 我了解C 中模板的方面与Java和C#中的泛型不同。C#是一种形式,Java使用类型擦除,C 使用鸭子类型,等等。C 模板可以做很多事情,而Java和C#泛型则做不到(例如,模板专业化)。但是 Java泛型可以做很多事情,而C#和C ++则做不到(例如,使泛型族的有界类型参数成为现实 ),而 C#泛型可以做的很多事情Java和C 不能做(例如运行时通用反射)。 [编辑:显然Java泛型