隐式转换为 const 类型时选择了错误的重载
Wrong overload selected when implicity converting to a const type
考虑以下代码:
#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
。当向 some_func
提供 a
时,第二个重载是 selected。这符合预期。其次,我创建了一个 double*
类型的变量 b
(所以没有 const
)。当向 some_func
提供变量 b
时,它 select 是第一个重载。我本来希望它是 select 第二次重载,因为(我认为)它应该能够隐式地将类型 double*
转换为 const double*
。为什么在这种情况下 select 是第一次重载而不是第二次重载?
为了完整性,这是程序的输出:
$ g++ main.cpp
$ ./a.out
Using the function accepting a const double*
Using the general function
限定词const
是一种契约。这意味着函数将无法通过指针更改值
所以编译器有两个选择:
- 要么从模板中实例化一个函数,该函数将能够(可能)更改值。
- 使用更严格的函数将无法更改它。
有可以改变的参数,选择第一种情况是合乎逻辑的。
因此,遵循精确类型选择规则,同时考虑 CV 限定符非常合乎逻辑。
在模板实例化期间,此 const SomeType p
会变成 double* const p
,这比 const double*
更匹配。也就是说,模板的参数将成为指向可变数据的常量指针。
在模板函数中,实际上可以通过那个指针修改数据,所以可以假设它是一个更好的匹配。
如果将 const SomeType p
更改为 const SomeType* p
,将选择特定的重载。
考虑以下代码:
#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
。当向 some_func
提供 a
时,第二个重载是 selected。这符合预期。其次,我创建了一个 double*
类型的变量 b
(所以没有 const
)。当向 some_func
提供变量 b
时,它 select 是第一个重载。我本来希望它是 select 第二次重载,因为(我认为)它应该能够隐式地将类型 double*
转换为 const double*
。为什么在这种情况下 select 是第一次重载而不是第二次重载?
为了完整性,这是程序的输出:
$ g++ main.cpp
$ ./a.out
Using the function accepting a const double*
Using the general function
限定词const
是一种契约。这意味着函数将无法通过指针更改值
所以编译器有两个选择:
- 要么从模板中实例化一个函数,该函数将能够(可能)更改值。
- 使用更严格的函数将无法更改它。
有可以改变的参数,选择第一种情况是合乎逻辑的。
因此,遵循精确类型选择规则,同时考虑 CV 限定符非常合乎逻辑。
在模板实例化期间,此 const SomeType p
会变成 double* const p
,这比 const double*
更匹配。也就是说,模板的参数将成为指向可变数据的常量指针。
在模板函数中,实际上可以通过那个指针修改数据,所以可以假设它是一个更好的匹配。
如果将 const SomeType p
更改为 const SomeType* p
,将选择特定的重载。