Что происходит с функцией, когда я указываю тип аргумента auto?
Такое объявление функции эквивалентно шаблону функции:template<typename T>
void print(T x) {
    std::cout << x << std::endl;
}
При компиляции будут созданы 3 функции print<int>, print<const char*>, print<char>.
Кстати, предупреждая возможные будущие ошибки: при таком использовании auto, функция print принимает все аргументы по значению, а в подобных ситуациях часто лучше по ссылке. С этой точки зрения более корректным может быть одно из следующих объявлений:void print(const auto& x) {
  std::cout << x << std::endl;
}
void print(auto& x) {
  std::cout << x << std::endl;
}
Читать
В Explanation Вы найдете ответ