【问题标题】:Overload resolution of function dependent on template parameter依赖模板参数的函数重载解析
【发布时间】:2020-09-27 10:50:28
【问题描述】:

在下面的示例中,函数模板 (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的重载版本取决于使用模板时可用的内容,以便用户可以为他使用的任何类型T实现square

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

【问题讨论】:

  • 可以添加主函数吗?
  • @yaodav 示例完成(试试gcc.godbolt.org/z/n7bcqr)。
  • 应该只考虑在quartic 之前声明的函数。我觉得奇怪的是 MSVC 使用 double 版本。
  • @TedLyngmo 默认情况下,MSVC 总是在模板实例化时查找,这与标准要求的不同。但它可以通过编译标志禁用。
  • ...那个标志是/permissive-。用它来让 MSVC 在几个方面更正确。

标签: c++ templates overloading


【解决方案1】:

函数模板quartic 中的square 是一个依赖名称,这意味着它依赖于模板参数T,并且它的查找被推迟到@ 987654328@ 是已知的。此外,它是一个非限定名称限定名称看起来像std::cout),这意味着它不仅会在其命名空间中查找但是参数的命名空间,这叫做argument-dependent lookupADL.

所以在这种情况下:

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

显然,不允许您的示例通过非 ADL 查找 工作。 ADL 也没有,因为 ADL 不考虑double

但如果参数是用户定义的类型,它由 ADL 工作。更清楚地说,如果你想调用定义在 this 作用域后面的函数,你可以使该函数通过 ADL 可见,这意味着函数和参数的类型(或间接类型,请参阅[2]) 在同一个命名空间中。

参考:

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

【讨论】:

    【解决方案2】:

    应该只考虑在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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-23
      • 1970-01-01
      • 1970-01-01
      • 2019-04-20
      • 2011-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多