函数的重载分辨率取决于模板参数

时间:2020-09-27 10:50:28

标签: c++ templates overloading

在下面的示例中,函数模板(quartic)使用重载的全局函数(square)。编译时,仅考虑在模板本身之前声明的重载,因此即使使用模板之前声明了square(int),也使用square(double)而不是square(double)

int square(int);

template<typename T>
T quartic(T value) {
    return square(square(value));
}

double square(double);

double x(double y) {
    return quartic(4.0); // Uses square(int), wanted square(double)
}

有没有一种方法可以使square的哪个重载版本的分辨率取决于使用模板时可用的内容,以便用户可以为任何类型square实现T }他使用了吗?

注意:奇怪的是,MSVC将使用square(double),而GCC,clang和icc使用square(int)

2 个答案:

答案 0 :(得分:4)

函数模板square中的quartic 依赖名称 ,这意味着它取决于模板参数T和其查找被推迟到知道T为止。此外,它是一个 不合格名称 (一个合格名称看起来像std::cout),这意味着它不仅可以在其名称空间,但参数的名称空间,称为 依赖于参数的查找 ADL < / em>。

在这种情况下:

  • 非ADL查找 检查具有外部链接的函数声明,这些声明在 模板定义上下文 中可见。 (原因在[1]中进行了解释)
  • ADL 检查具有外部链接的函数声明,这些声明从 模板定义上下文 或< em> 模板实例化上下文

很明显,不允许通过非ADL查找让示例工作。而且 ADL 也不这样做,因为 ADL 没有考虑double

,但是如果参数是用户定义的类型,则它由 ADL 使用。更清楚地讲,如果要调用在此作用域后定义的函数,则可以使该函数 通过ADL可见 ,这表示该函数和参数的类型(或间接类型,请参见[2])在同一名称空间中。

参考:

  1. https://en.cppreference.com/w/cpp/language/dependent_name
  2. https://en.cppreference.com/w/cpp/language/adl

答案 1 :(得分:1)

仅应考虑在quartic之前声明的函数,因此MSVC做错了。解决此问题的一种可能方法是也使square成为功能模板,并让用户为其提供专门化功能。

您的代码:

template<typename T> T square(T);

template<typename T>
T quartic(T value) {
    return square(square(value));
}

用户代码:

template<> int square(int value) {
    return value * value;
}

template<> double square(double value) {
    return value * value;
}