根据我的理解,const指针函数参数应该能够接受const和非const指针。在后一种情况下,通过指针修改值是非法的。
假设我具有以下模板功能
template <typename T1, typename T2>
decltype(auto) plus(T1 a, T2 b) {
return a + b;
}
template <typename T1, typename T2>
decltype(auto) plus(const T1* a, const T2* b) {
return *a + *b;
}
int main() {
int a {2}, b {3};
std::cout << plus(a, b) << std::endl;
int *first { new int {2} }, *second { new int {3} };
// it seems here that the return type is deduced to be void*?
std::cout << plus(first, second) << std::endl;
}
第二个函数调用正确调用了plus
模板函数,该模板函数接受指针参数,但将返回类型推导为void*
但是,如果我将模板签名更改为
template <typename T1, typename T2>
decltype(auto) plus(T1* a, T2* b) {
return *a + *b;
}
这将产生正确的结果。
这里发生了什么?
plus(first, second)
调用第一个模板重载,因为它是更好的匹配。
在模板参数推导后(拳头为T1 == T2 == int*
,第二位为T1 == T2 == int
),两个重载都是可行的。但是,对于这两个参数中的每个参数,第一个重载仅需要从左值到右值的转换,而第二个重载则需要从左值到右值的转换,然后是限定符转换(加const
)。
因此,两个参数的隐式转换序列对于第一次重载都是更好,因此可以通过重载分辨率来选择。甚至不考虑功能模板的部分排序。
但是用T1 == T2 == int*
调用第一个功能模板是错误的,因为如果a + b
和a
都是指针类型,则不允许b
。您的编译器应该已经在这里给您一个错误。
有了第二个模板重载的替代签名,就不需要上述附加的资格转换,并且两个重载的参数的隐式转换顺序将是相同的。
因此,将考虑功能模板的局部排序来决定选择哪个重载,并且由于第二个模板比第一个模板更加专业,因此将选择第二个模板。
然后使用T1 == T2 == int
,它将按预期方式工作,因为*a + *b
加了两个int
,而不是两个指针,返回的类型为int
,因为*a + *b
是prvalue。