【问题标题】:Wrong overload selected when implicity converting to a const type隐式转换为 const 类型时选择了错误的重载
【发布时间】:2021-11-18 03:23:27
【问题描述】:

考虑下面的代码:

#include <iostream>

// General overload using a template
template <typename SomeType>
void some_func(const SomeType p) {
    std::cout << "Using the general function" << std::endl;
}

// Specific overload, accepting a 'const double*' type
void some_func(const double* p) {
    std::cout << "Using the function accepting a const double*" << std::endl;
}

int main() {
    // This one uses the specific overload, as expected
    const double *a = new double(1.1);
    some_func(a);
    delete a;
    
    // This one uses the general function rather than the second overload
    double *b = new double(1.1);
    some_func(b);
    delete b;
    
    return 0;
}

在这段代码中,some_func 函数有两个重载。第一个是最常见的重载,使用模板来捕获几乎任何类型。第二个重载是一个特定的重载,接受 const double* 类型作为其参数。

main 函数中,我首先创建const double* 类型的变量a。将a 提供给some_func 时,将选择第二个过载。这正如预期的那样。其次,我创建了一个double* 类型的变量b(所以没有const)。当将变量b 提供给some_func 时,它会选择第一个重载。我预计它会选择第二个重载,因为(我认为)它应该能够将类型double* 隐式转换为const double*。为什么在这种情况下它选择第一个重载而不是第二个重载?

为了完整起见,这是程序的输出:

$ g++ main.cpp
$ ./a.out
Using the function accepting a const double*
Using the general function

【问题讨论】:

  • 提示:您希望p 在每个函数中具有什么值?
  • 参数应完全匹配,以便编译器选择非模板函数。所以选择不是“错误的”。
  • 如果您将函数编写为 void some_func(double const * p) 与您所拥有的相同,为什么首选模板是否有意义?
  • @chux-ReinstateMonica 在将b 传递给some_func 时,我希望p 在两个重载中都具有const double * 类型。然而,事实证明p 在模板化重载中属于double* const 类型,在特定重载中属于const double* 类型。考虑到这一点,我理解它为什么使用模板化重载。

标签: c++ implicit-conversion overload-resolution


【解决方案1】:

在模板实例化期间,这个const SomeType p 会变成double* const p,这比const double* 更匹配。也就是说,模板的参数将成为指向可变数据的常量指针。
在模板函数中,您实际上可以通过该指针修改数据,因此可以认为它是一个更好的匹配。
如果把const SomeType p改成const SomeType* p,就会选择具体的重载。

【讨论】:

  • 感谢您的解释!除了将const SomeType p 更改为const SomeType* p 之外,还有其他方法可以确保在传递double * 时使用特定的重载吗?不幸的是,实际代码不允许进行这种更改。
  • 这取决于你的情况。您可以使用 SFINAE,例如 std::enable_if,或者使用 if constexpr() 检查类型。但是,如果您无法更改模板,那么我认为您可以这样做的唯一方法是添加另一个与类型理想匹配的特定重载,并且在其中您可以将值强制转换为 const 并调用原始的特定重载。
【解决方案2】:

限定符const 是一种契约。这里的意思是函数不能通过指针改变值

所以编译器有两种选择:

  1. 要么从模板中实例化一个函数,该函数将能够(可能)更改值。
  2. 使用无法更改的更严格的函数。

有了可以改变的论点,选择第一种情况是合乎逻辑的。

因此,遵循以精确类型选择的规则,考虑到 CV 限定符非常合乎逻辑。

【讨论】:

    猜你喜欢
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多