[БЕЗ_ЗВУКА] Давайте еще раз посмотрим на то, как мы запускаем юнит-тесты в нашем фреймворке. Мы уже обращали внимание, что нам приходится дублировать имя функции, содержащей тесты, чтобы оно выводилось на экран. И мы хотим от этого дублирования избавиться, и в этом нам помогут макросы. Давайте для начала напишем вот такой макрос. RUN_TEST, который принимает параметр tr — это объект класса TestRunner. Я специально назвал его tr, чтобы было понятно, что это тот самый tr. И func, func — это собственно функция, содержащая тесты. И что этот тест будет делать? Он будет у объекта tr вызывать метод RunTest, передавать туда func и еще раз func. И давайте вот здесь вот мы этот макрос применим. Мы заменяем RUN_TEST, делаем вот так и повторяем это еще раз. [БЕЗ_ЗВУКА] Вот. Мы берем наш макрос RUN_TEST, передаем туда объект класса TestRunner и тестовую функцию. Если мы сейчас запустим компиляцию, то наша программа, естественно, не скомпилируется. Почему? Потому что наш макрос берет и нашу тестовую функцию передает в метод RUN_TEST в качестве второго параметра. Этот параметр должен быть строкой. Давайте на всякий случай убедимся в этом. Я снова сделал применим препроцессинг и смотрю, какой у меня получился исходник. У нас макрос раскрылся, tr.RUN_TEST, и в качестве второго параметра передается имя функции. Поэтому, естественно, наш код не компилируется, вот здесь у нас какие-то там ошибки. Но теперь мы сделаем одну маленькую вещь. Мы перед вторым использованием параметра func в нашем макросе поставим символ решетки # и снова запустим компиляцию. Компиляция прошла успешно. Мы запускаем нашу программу и видим, что все работает и в консоль действительно выводятся тесты. Чтобы понять, что произошло, давайте снова выполним препроцессинг и посмотрим, что же стало с нашим исходником. Идем в конец файла, и мы видим, что теперь в качестве второго параметра передается имя функции, но обернутое в кавычки. То есть это строковый литерал, который является строковым представлением того параметра, который мы передали в наш макрос. То есть мы вот здесь вот указали в качестве параметра TestDefaultConstructor, и оператор # сделал для него строковое представление. То есть мы сюда на самом деле могли передать что угодно. И в результате препроцессинга это что угодно будет обернуто в кавычки, и из этого будет создана строковая константа. Таким образом, благодаря использованию оператора # мы добились одной из своих целей. Теперь, когда мы вызываем, юнит-тесты, мы это можем делать с помощью этого макроса RUN_TEST и не дублировать имя функции, а просто передавать эту функцию в этот макрос, и препроцессор за нас в качестве второго параметра передаст в метод RUN_TEST имя этой функции. Это отлично. Другой пример, когда оператор # в макросах бывает полезен, выглядит вот таким образом. Сейчас я открою пустой файл, так, это у нас осталось с прежнего примера. Иногда нам нужно что-то логировать, например, для отладки. Чаще всего это бывает полезно при отладке. Допустим, у нас есть какая-нибудь переменная x, которая равна 4. Еще есть какая-нибудь переменная t, которая равна hello. И например, что еще? Пусть у нас еще будет bool из true, которая равна false. И мы хотим для отладки выводить эти значения в какой-то поток. Например, мы можем выводить их в стандартный поток. Если мы их выведем просто вот так, [БЕЗ_ЗВУКА] то что мы увидим на экране? Мы увидим 4, hello, ноль. Но когда мы отлаживаем, мы хотим понимать, а что такое 4, например? У нас, допустим, много разных значений выводится, и мы забываем, что сначала идет значение переменной x, потом значение переменной t. Вот тут нам тоже могут помочь макросы и оператор #. Мы можем сделать такой макрос AS_KV — это as key value, как бы ключ-значение, который принимает один параметр x и раскрывается в #x = x. И давайте теперь им воспользуемся. AS_KV(x). AS _KV(t). Я даже перевод строки вставлю, чтобы лучше вывелось, и AS _KV(isTrue). И на самом деле еще для наглядности выведем булевские значения в виде строк. Компилируем. Компилируется. И мы видим, что теперь в консоли появились более понятные сообщения, что x = 4, t = hello, а переменная isTrue = false. Таким образом, с помощью этого макроса и с помощью оператора # мы смогли сделать более понятный, более удобочитаемый отладочный вывод. Давайте подведем итоги. В этом видео мы с вами узнали, что в макросах можно применять специальный оператор #, который вставляет в исходник строковое представление параметра макросов. И с помощью этого оператора # мы смогли достичь одной из своих целей: мы написали макрос RUN_TEST, который теперь избавил нас от необходимости дублировать имя функции в качестве второго параметра метода RUN_TEST в классе TestRunner нашего фреймворка.