Почему реализация MSVC _count_of добавляет 0 к результату sizeof?

Я читал реализацию _countof в MSVC и обнаружил деталь, которую не могу объяснить. Он реализован с помощью макроса __crt_countof, который на C++ расширяется до (sizeof(*__countof_helper(_Array)) + 0) (вот соответствующий код из заголовок). Почему там + 0? Что было бы не так без него?


person Kirill Dmitrenko    schedule 18.12.2019    source источник
comment
Я даже не могу разобрать это объявление __countof_helper...   -  person Max Langhof    schedule 18.12.2019
comment
@MaxLanghof Мне потребовалось некоторое время, чтобы разобрать его :) Он объявляет шаблон функции, который возвращает указатель на массив фиксированного размера с тем же количеством char, что и в массиве аргументов. Таким образом, sizeof этого массива char должно быть таким же, как количество элементов в массиве аргументов.   -  person Kirill Dmitrenko    schedule 18.12.2019
comment
@KirillDmitrenko Зачем он все это делает? Это кажется более интересным, чем +0. Не мог ли __countof_helper просто вернуть _SizeOfArray?   -  person François Andrieux    schedule 18.12.2019
comment
@FrançoisAndrieux Это безопаснее, чем традиционный sizeof(a) / sizeof(a[0]). Если вы случайно передадите указатель вместо статического массива в эту конструкцию, вы получите плохой результат. Связанная реализация не будет компилироваться для указателя. Вот аналогичный импл в Chromium и вот статья, содержащая полное объяснение, почему что-то подобное предпочтительнее и менее подвержено ошибкам (осмелюсь даже сказать, безошибочно).   -  person Kirill Dmitrenko    schedule 18.12.2019
comment
Я предполагаю, что этот код предшествует constexpr. И код, который я связал, компилируется, но на самом деле не запускается. Теперь я понимаю, почему это делается именно так. Он сообщает размер через информацию о типе, которая поддерживает постоянное время компиляции.   -  person François Andrieux    schedule 18.12.2019


Ответы (1)


+ 0 добавлен, чтобы предотвратить потенциальное появление самого неприятного разбора! Без него такое выражение, как sizeof(*__countof_helper(_Array)) могло бы восприниматься как объявление функции при некоторых обстоятельствах.

EDIT: в настоящее время я пытаюсь создать пример контекста (согласно запросу в комментарии). А пока может оказаться полезным этот сильно упрощенный «эквивалент» (то, с чем я действительно сталкивался):

#include <iostream>
#include <vector>

int main() {
    int num = 2;
//  std::vector<char> vec(size_t(num));     // Won't compile - Most Vexing Parse
    std::vector<char> vec(size_t(num) + 0); // Compiles - no longer a func decl!
    vec[0] = 'a';
    vec[1] = 'b';
    std::cout << vec[0] << ' ' << vec[1] << std::endl;
    return 0;
}
person Adrian Mole    schedule 18.12.2019
comment
Можете ли вы поделиться примером контекста, в котором это происходит? - person François Andrieux; 18.12.2019
comment
Дополнительные скобки вокруг size_t(num) также фиксируют это, что есть в макросе. Так что мне кажется, что макрос уже защищает от этого без +0. - person François Andrieux; 18.12.2019
comment
@FrançoisAndrieux Но кодер M / S, который реализовал этот конкретный заголовок, возможно, не был уверен, поэтому добавил +0 на всякий случай? - person Adrian Mole; 18.12.2019
comment
Определенно возможность. Намерение могло состоять в том, чтобы предотвратить mvp. В любом случае это не вредит, и логично, что никто не хочет брать на себя ответственность за его удаление и рисковать случайно взломать чей-то код, если окажется, что он делает что-то неожиданное. - person François Andrieux; 18.12.2019
comment
@FrançoisAndrieux Можно возможно «разбить» добавленные круглые скобки, попытавшись определить операцию приведения/преобразования с помощью: #define BESILLY(arg) int _countof(arg) - person Adrian Mole; 18.12.2019
comment
sizeof не size_t. Это не тип. Я не понимаю, как это может вызвать MVP. - person T.C.; 18.12.2019
comment
@Т.С. Точно в точку. Мои попытки придумать пример пока не увенчались успехом! Я могу сделать это с size_t, но нет с sizeof! Здесь я могу только предположить, что, возможно, было время (все еще может быть когда-нибудь?), когда sizeof был реализован в функциональном стиле. И давайте не будем забывать, что лучше не исправлять чужой код, если вы не знаете, почему вы его «исправляете». - person Adrian Mole; 19.12.2019
comment
Можете ли вы привести какой-либо источник, что это является причиной этого? Парень, который на самом деле написал код, говорит другое. - person M.M; 19.12.2019
comment
@M.M Я могу только отослать вызывающего абонента к моему комментарию выше или, может быть, к этой альтернативе: /а> - person Adrian Mole; 19.12.2019