алгоритм подсчета и типы указателей

Я написал следующий код в качестве упражнения о шаблонах функций и специализациях шаблонов. Это функция, которая подсчитывает, сколько объектов данного типа присутствует в vector:

template <typename T>
int function(const std::vector<T> &vec, T val) {
int count = 0;
for(typename std::vector<T>::const_iterator it = vec.begin(); it != vec.end(); ++it)
if(*it == val)
++count;
return count;
}

template <>
int function(const std::vector<const char*> &vec, const char* val) {
int count = 0;
for(std::vector<const char*>::const_iterator it = vec.begin(); it != vec.end(); ++it) {
if (std::string(*it) == std::string(val))
++count;
}
return count;
}

Я написал код в специализации, потому что хочу знать, совпадает ли каждый символ в слове с данным литералом. К моему удивлению, если я закомментирую специализацию и позволю компилятору создать исходный шаблон, он будет работать даже для массивов const char:

int main() {
std::vector<const char*> cvec = {"hi", "hi", "hallo", "hej", "hej", "hi", "hej", "hej", "hej"};
std::cout << function(cvec, "hej") << std::endl;
}

Живая демо

Как это могло быть?

1

Решение

Я использую код в своей основной функции, чтобы протестировать его, но, к моему удивлению, если я закомментирую специализацию и позволю компилятору создать исходный шаблон, он будет работать даже для массивов const char (тип строкового литерала) ! Как это могло быть?


Стандарт не устанавливает, что строковые литералы, содержащие одинаковую последовательность символов, должны храниться в той же ячейке памяти, что и в §2.13.5 / 16:

Оценка строкового литерала приводит к получению строкового литерала со статической продолжительностью хранения, инициализированного из заданных символов, как указано выше. Все ли строковые литералы различны (то есть хранятся в неперекрывающихся объектах) и не определены ли последовательные вычисления строкового литерала того же самого или другого объекта.

(акцент мой)

но эта реализация разрешена, и это то, что здесь происходит: каждая литеральная строка "hej" хранится в том же адресе памяти, поэтому == на const char* проверяет, является ли адрес тем же и дает значение true.


Чтобы «доказать» это, нам просто нужно взглянуть на этот пример:

int main() {
std::vector<const char*> cvec = {"hi", "hi", "hallo", "hej", "hej", "hi", "hej", "hej", "hej"};
std::cout << function(cvec, "hej") << '\n';
}

Живая демо

Это дает 5 из-за того, что есть 5 литералов "hej" в векторе. Но если мы добавим еще char массив с таким же точным chars в буквальном смысле, что мы знаем, должен иметь другой адрес:

int main() {
std::string hej = "hej";
std::vector<const char*> cvec = {"hi", "hi", "hallo", "hej", "hej", "hi", "hej", "hej", "hej", hej.c_str()};
std::cout << function(cvec, "hej") << std::endl;
}

Живая демо

Затем мы видим, что количество не меняется.

4

Другие решения