Перегрузка функций - выбор между типом параметра массива и указателя
Есть два шаблона функции, одна из них принимает ссылку на массив char, вторая - указатель на char. Если мы вызываем функцию, передавая ей в качестве параметра строковый литерал, то все работает как и ожидается - инстанцируется шаблон с параметром массива.
template <size_t n>
void f(const char (&)[n])
{
std::cout << "-- char []" << std::endl;
}
template <typename>
void f(const char *)
{
std::cout << "-- char *" << std::endl;
}
int main()
{
f("abc");
return 0;
}
-- char []
Но если мы добавим в параметры шаблонов тип элементов массива/указателя, то компилятор выдает ошибку неоднозначности выбора:
template <typename t, size_t n>
void f(const t (&)[n])
{
std::cout << "-- char []" << std::endl;
}
template <typename t>
void f(const t *)
{
std::cout << "-- char *" << std::endl;
}
int main()
{
f("abc");
return 0;
}
a.cpp:63:8: error: call of overloaded ‘f(const char [4])’ is ambiguous
Почему в данном случае компилятор не может выбрать функцию, и как это побороть?
Ответы (2 шт):
В первом случае функция f(const char *) вообще не может быть вызвана без явного указания параметра шаблона, так как он не выводится из аргументов. А во втором - выводится, вот и получается неопределенность. Чтобы различить передачу массива и указателя, во втором случае указатель тоже нужно принимать по ссылке:
#include <iostream>
#include <stddef.h>
template <typename t, size_t n>
void f(t const ( & )[n])
{
std::cout << "-- char []" << std::endl;
}
template <typename t>
void f(t const * const &)
{
std::cout << "-- char *" << std::endl;
}
int main()
{
f("abc");
f(static_cast<char const *>("abc"));
return 0;
}
-- char []
-- char *
Встроенный тип строки как массив символов имеет способность автоматического преобразования типа на указатель на первую букву. Чтобы не было такой проблемы желательно использовать собственный тип без преобразования. И тогда заданную строку как массив передавать как свой тип.
# include <cstdlib>
# include <iostream>
template <typename t , size_t n >
struct ConstArray {
t const ( & a ) [ n ] ;
ConstArray(t const ( & x ) [ n ]):a{x}{}
} ;
template <typename t ,size_t n>
void f(ConstArray<t,n> const & )
{
std::cout << "-- char []" << std::endl;
}
template <typename t>
void f(const t *)
{
std::cout << "-- char *" << std::endl;
}
int main()
{
f("abc");
f(ConstArray{"abc"});
return 0;
}