Продолжение моей предыдущей регистрации.
Шаблоны являются одной из главных причин, почему C++ перестал работать так плачевно в intellisense, независимо от используемого IDE. Из-за шаблонной специализации IDE никогда не может быть действительно уверен, существует ли данный участник или нет. Рассмотрите:
template <typename T>
struct X {
void foo() { }
};
template <>
struct X<int> { };
typedef int my_int_type;
X<my_int_type> a;
a.|
Теперь, курсор в обозначенном положении, и это чертовски трудно для IDE для высказывания в той точке, если, и что, имеют участники a
. Для других языков парсинг был бы прост, но для C++, довольно мало оценки необходима заранее.
Это ухудшается. Что, если my_int_type
были определены в шаблоне класса также? Теперь его тип зависел бы от другого аргумента типа. И здесь, даже сбой компиляторов.
template <typename T>
struct Y {
typedef T my_type;
};
X<Y<int>::my_type> b;
После небольшого количества взглядов, программист пришел бы к заключению, что этот код совпадает с вышеупомянутым: Y<int>::my_type
твердость к int
, поэтому b
должна быть тем же типом как a
, правильно?
Неправильно. В точке, где компилятор пытается разрешить этот оператор, он еще на самом деле не знает Y<int>::my_type
! Поэтому это не знает, что это - тип. Это могло быть что-то еще, например, функция членства или поле. Это могло бы дать начало неоднозначностям (хотя не в данном случае), поэтому компилятор перестал работать. Мы должны сказать ему явно, что обращаемся к имени типа:
X<typename Y<int>::my_type> b;
Теперь, компиляции кода. Чтобы видеть, как неоднозначности являются результатом этой ситуации, рассмотрите следующий код:
Y<int>::my_type(123);
Этот оператор кода совершенно допустим и говорит C++ выполнять вызов функции к [1 111]. Однако, если бы my_type
не функция, а скорее тип, этот оператор все еще был бы допустим и выполнил бы специальный бросок (бросок функционального стиля), который часто является вызовом конструктора. Компилятор не может сказать, который мы имеем в виду, таким образом, мы должны снять неоднозначность здесь.
это слишком дорогой способ объединения файлов.
cat ../best-practices/*.textile > ../best_practices.textile
, если вы хотите добавить пробел (новую строку) к каждому файлу при объединении, используйте awk
awk 'FNR==1{print "">"out.txt"}{print > "out.txt" }' *.textile
ИЛИ
awk 'FNR==1{print ""}{print}' file* > out.txt
Это позволяет вам вставлять новые строки между каждым входным файлом, как вы это делали в исходном скрипте:
for f in $FILES; do echo -ne '\n\n' | cat "$f" -; done > $OUTPUT
Обратите внимание, что $ FILES
не цитируется, чтобы это работало (в противном случае дополнительные символы новой строки появляются только один раз в конце всего вывода), но $ f
необходимо заключить в кавычки, чтобы защитить пробелы в именах файлов, если они существуют.
Как отмечали другие, использование cat или awk вместо цикла чтения-эха - гораздо лучший способ сделать this - позволяет избежать проблемы с обрезкой пробелов (и пары других, на которые вы еще не наткнулись), работает быстрее и, по крайней мере, с cat, это просто более чистый код. Тем не менее, я хотел бы попытаться заставить цикл чтение-эхо работать правильно.
Во-первых, проблема обрезки пробелов: команда чтения автоматически обрезает начальные и конечные пробелы; это можно исправить, изменив определение пробела, установив для переменной IFS пустое значение. Кроме того, read предполагает, что обратная косая черта в конце строки означает, что следующая строка является продолжением и должна быть соединена с этой; чтобы исправить это, используйте его флаг -r (raw). Третья проблема заключается в том, что многие реализации эхо интерпретируют escape-последовательности в строке (например, они могут превратить \ n в фактическую новую строку); чтобы исправить это, используйте вместо этого printf. Наконец, как и общее правило гигиены сценариев, вы не должны использовать cat, когда вам это действительно не нужно; вместо этого используйте перенаправление ввода. С этими изменениями внутренний цикл выглядит так:
while IFS='' read -r line; do
printf "%s\n" "$line">>$OUTPUT
done <$f
... есть еще пара проблем с окружающим скриптом: строка, которая пытается определить ФАЙЛЫ как список доступных файлов .textile, заключена в кавычки, это означает, что он никогда не расширяется до фактического списка файлов. Лучший способ сделать это - использовать массив:
FILES=(../best-practices/*.textile)
...
for f in "${FILES[@]}"
(и все вхождения $ f должны быть заключены в двойные кавычки на случай, если в каком-либо из имен файлов есть пробелы или другие забавные символы - действительно следует делать это с помощью $ ВЫХОД, хотя, поскольку это определено в сценарии, на самом деле безопасно его оставить.)
Наконец, есть echo ""> $ OUTPUT
в верхней части циклических файлов, которые собираются стереть вывод файл каждый раз (т.е. в конце он содержит только последний файл .textile); это нужно переместить до цикла. Я не уверен, что здесь имелось в виду поместить одну пустую строку в начало файла или три пустые строки между файлами (одну в начале и две в конце), поэтому я не уверен, что именно соответствующая замена есть. В любом случае, вот что я могу сделать после исправления всех этих проблем:
#!/bin/sh
OUTPUT="../best_practices.textile"
FILES=(../best-practices/*.textile)
: >"$OUTPUT"
for f in "${FILES[@]}"
do
echo "Processing $f file..."
echo >>"$OUTPUT"
while IFS='' read -r line; do
printf "%s\n" "$line">>"$OUTPUT"
done <"$f"
echo >>"$OUTPUT"
echo >>"$OUTPUT"
done