LINUX.ORG.RU

Как в C++11 принято разделять реализацию и объявление шаблонных классов

 ,


0

5

В общем есть класс шаблонный у которого есть шаблонные методы, как можно реализовать разделение на .h и .cpp без вот таких вот костылей в cpp'шнике?

template class DataField<long>;
template class VariantsDataField<long>;
template VariantsDataField<long> VariantsDataField<long>::operator *<long>(VariantsDataField<long>);
template VariantsDataField<long> VariantsDataField<long>::operator /<long>(VariantsDataField<long>);
?

★★★★★
Ответ на: комментарий от deterok

Решения нет. Привыкай, таков спп. Он будет тебе мешать всегда и всюду. Что бы ты не придумал, спп всегда будет иметь ограничения, которые заставят тебя либо использовать костыли, либо переделать всё, что ты придумал. Со временем, когда ты наберёшься опыта, эти проблемы может быть и исчезнут, но до этого пройдёт лет пять. Но даже тогда ты будешь спотыкаться на каких-то эфемерных хренотенях, о которых знают даже не все члены комитета. Спп - это ад.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

Я еще и питоньщик :)

Ушел от ++ года 2 назад, сейчас вот один проектик взял.

deterok ★★★★★
() автор топика
Ответ на: комментарий от Pavval

Что? В эрланге нет такой проблемы вообще, ты что-то путаешь. Там весь код по сути типонезависим. Вот тебе пример работающий и с целыми и вещественными числами:

f(X) ->
  X*X;
А вот это что-то в духе, ммм..., даже не знаю... в сплюс-сплюсе такое есть вообще? Откомпелированые шаблончики в объектниках не сохранить, да)
f({my_type, Data}) ->
  Data ! please_double,
  receive Any -> Any end;
f(X) -> X*X.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

Вот тебе пример работающий и с целыми и вещественными числами:

И падающий в рантайме при попытке применить эту функцию к чему-то ещё. В крестах хоть какая-то типизация есть, и уже поэтому эрланг у них отсасывает.

anonymous
()
Ответ на: комментарий от anonymous

И падающий в рантайме

Я ждал, что ты это напишешь. И вот слушай сюда, я отвечаю тебе на подобные дебильные вопросы один раз.

Если ты пишешь, что-то, что должно принимать только числа, то в эрланге ты просто пишешь эту ф-ию и всё. Если тебе нужна защита от дурака, ты пишешь:

f(X) when is_integer(X); is_float(X) -> X*X;
f(_) -> sam_durak.
, чего вообще в эрланге никто не делает ибо нафиг не нужно. А теперь внимание, если ты сейчас начнёшь мне говорить, что в твоих сплюсах можно сделать так вернув код ошибки, я тебе скажу что тебе придётся писать кучу ифов и свичей, т.е. говнокодить по обезъяни. А если ты мне скажешь про throw sam_durak, то я тебе напомню, что тебе как минимум необходимо определить тип sam_durak, что при само по себе в далёкой перспективе задолбёт, а во-вторых напомни мне пожалуйста причины использовать сплюс, ах да - производительность. Производительность'n'исключения, помноженные на raii и раскрутку стека - вот веселуха! Сплошная производительность, да.

И да, man dyalizer уже наконец.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

man dyalizer уже наконец.

Долго объяснять про то, как ловко Эрланг обходится без статической типизации, а потом ненавязчиво отослать к костылю, реализующему эту самую типизацию.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Всё верно. А что тебе не нравиться? Ты бы ещё придрался к отсутствию знака пунктуации во фразе „то тебе как минимум необходимо определить тип sam_durak“.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

А что тебе не нравиться?

То, что ты -тся и -ться не освоил, а еще пытаешься кукарекать про ненужность плюсов.

Solace ★★
()
Ответ на: комментарий от tailgunner

Ты не понял. Ему бесполезно объяснять, что то, что он назвал „падучее“ на самом деле не то же самое, что и „падучее“ в терминах сплюса. Отвалившийся процесс в эрланге - это так же как и эксепшн. Я же не кричу, что сплюс ущербный из-за того, что там выкидывают эксепшены, правда? На самом деле он действительно ущербный, но не из-за эксепшенов.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

Я ждал, что ты это напишешь. А теперь расскажи,

1) сколько строк было в самом большом эрланг-проекте, с которым ты работал

2) сколько времени он писался

3) сколько человек над ним работало

t. работаю с огромным проектом на этом недоязычке и знаю кое-что о масштабировании

P.S.

Если тебе нужна защита от дурака, ты пишешь:

Руками писать проверку типов

madotsuki_vomit.jpg

anonymous
()
Ответ на: комментарий от nanoolinux

А теперь внимание, если ты сейчас начнёшь мне говорить, что в твоих сплюсах можно сделать так вернув код ошибки, я тебе скажу что тебе придётся писать кучу ифов и свичей,

P.P.S. Да ты и верно ущербный! Чтобы сделать такое в плюсах, мне не нужно писать ровно ни одной строчки, ибо статическая типизация для того и нужна.

anonymous
()
Ответ на: комментарий от nanoolinux

А теперь внимание, если ты сейчас начнёшь мне говорить, что в твоих сплюсах можно сделать так вернув код ошибки, я тебе скажу что тебе придётся писать кучу ифов и свичей, т.е. говнокодить по обезъяни.

Серьёзно что ли? http://ideone.com/5S9Gxe

anatoly
()
Ответ на: комментарий от nanoolinux

Ты не понял

Я понял.

то, что он назвал „падучее“ на самом деле не то же самое, что и „падучее“ в терминах сплюса

Похоже, это ты не понял. Он говорит (и я тоже), что программа на Эрланге может содержать ошибки, которые тривиально отлавливаются любым компилятором статически типизированного языка.

Я же не кричу, что сплюс ущербный из-за того, что там выкидывают эксепшены, правда?

Еще раз - речь не об этом. Речь о том, что программа на Эрланге (и любом динамически типизированном языке) может «выкидывать исключения» на тривиально обнаруживаемые вещи.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от nanoolinux

Там часть, соответствующая твоему, занимает не 40, а 15 строк.

Но как выше уже сказал анон смысла на С++ такое ноль, т.к. эта та ошибка, которая должна отлавливаться на этапе компиляции.

Ну и код тот можно сократить до трёх строк.

Вот с неправильным вызовом и ошибкой компиляции:

http://ideone.com/QwdO6D

А вот рабочий:

http://ideone.com/vzKdgA

anatoly
()
Ответ на: комментарий от nanoolinux

На самом деле безопасная реализация (внезапно!) будет выглядеть так:

template <typename T>
T foo(T a, T b) {
  return a*b;
}

Ну а ежели хочется совсем перестраховаться, или тайпклассы хаскеля не дают покоя, то можно воспользоваться type_traits, но мне не охота вспоминать, как это делается.

anonymous
()
Ответ на: комментарий от anonymous

Согласен.

Т.е. целевой эрланговский код сокращаяется до одной строчки:

template <typename T> T f(T v) { return v*v; }

Убедительная победа С++ над Эрлангом!

anatoly
()
Ответ на: комментарий от nanoolinux

Отвалившийся процесс в эрланге - это так же как и эксепшн.

О, да, конечно.

Рассказываю историю из недавних.

Вдруг, после очередного обновления, отвалился некий сервис, назовём его A. Причём отвалился насовсем. Отладочные логи показали, что сервис отваливается всегда, через пару минут после запуска системы, в непредсказуемом месте. То есть, не «строка 666 содержит ошибку, сервис падает», а просто где попало. Самое интересное, что код A с предыдущего релиза не меняли вообще.

Оказалось, в конце концов, вот что. Сервис A висел под супервизором. Под этим же супервизором висел другой сервис B. Этот сервис был реализован как gen_server - вот только одна из handle_* функций в нём возвращала не то. Вместо {noreply, Something} возвращала {ok, Something}.

Сервис, естественно, падал, после чего супервизор его заботливо перезапускал и всё работало с самого начала. В логах, естественно, падение отражалось, но портянка там такая, что никто ничего не заметил, да и не пытался - всё ведь работает.

Что-то мы там наоптимизировали. Сервис B стал работать в разы быстрее. И падать чаще. Соответственно, увидев, что сервис падает уж очень часто, супервизор сказал «всё, ребята, я задолбался», убил всех своих детей (в том числе сервис A, ни в чём не повинный) и убился сам. Всё.

В языке со статической типизацией оно бы не скомпилировалось вообще. И мы увидели бы ошибку на полгода раньше.

И только не говори мне, что с эксепшенами бывает так же или даже хуже. Теоретически - может быть, но на практике - не верю.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

Ты тоже что ли на ырланге пишешь? Мои соболезнования.

Самое отвратительное в динамике — это даже не баги, а сам процесс девелопмента. Чтобы понять, что тебе прилетит в функцию, надо лезть в чужую подсистему, в код, авторы которого пять лет назад сторчались и померли от спида, и потом держать это в памяти на будущее. Омерзительно.

anonymous
()
Ответ на: комментарий от anonymous

Спасибо. Ничего, это не надолго.

Чтобы понять, что тебе прилетит в функцию, надо лезть в чужую подсистему, в код, авторы которого пять лет назад сторчались и померли от спида, и потом держать это в памяти на будущее. Омерзительно.

Угу. У нас на все функции есть -spec, вот только никто, в том числе диалайзер, не гарантирует, что туда не прилетит какая-нибудь лажа.

Miguel ★★★★★
()
Ответ на: комментарий от NegatiV

Неужели тесты отрабатывали правильно?

Угу. Всё ведь работало. Сервис B завершал цикл - и, вместо того, чтобы перейти на его начало, падал. И поднимался супервизором. Всё почти так же, как при нормальном функционировании.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

Что-то подобное и у нас случалось: переполнялся почтовый ящик у процесса и сервер отваливался. Из-за ошибки в match pattern. :)

NegatiV
()
Ответ на: комментарий от Miguel

В языке со статической типизацией оно бы не скомпилировалось вообще.

Статическая типизация тут бы никак не помогла.

В плюсах ты бы из функции возвращал какую-нибудь перемунную типа

enum class result { ok, noreply }

И тебе бы ничто там не мешало точно так же вместо result::noreply написать result::ok.

Ошибку бы заметили из-за того, что сервис падает.

А что мешало протестировать сервис без перезапусков или сделать проверку возвращаемого значения?

Ну и то что в логи никто не смотрел говорит скорее о том, что у вас там изъяны в методике разработки, а не неудачно подобранный инструмент.

И мы увидели бы ошибку на полгода раньше.

А, возможно, что и нет. Т.к. на плюсах писали бы программу на полгода дольше.

anatoly
()
Ответ на: комментарий от anatoly

Статическая типизация тут бы никак не помогла.

Товарищ, вы в уме?

И тебе бы ничто там не мешало точно так же вместо result::noreply написать result::ok.

Нет. Потому что там НЕТ варианта ok. Там есть reply, noreply и stop. И падало оно ИМЕННО потому, что возвращался неподходящий по типу результат.

А что мешало протестировать сервис без перезапусков или сделать проверку возвращаемого значения?

Сервис включён в экосистему, в отрыве от неё он не работает.

А проверка возвращаемого значения уже есть, в gen_server. Она-то и крашила сервис, возвращавший не то.

Т.к. на плюсах писали бы программу на полгода дольше.

Речь шла не о плюсах vs эрланг, а о статической типизации vs типизация эрланга. Языков со статической типизацией много.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

Товарищ, вы в уме?

А вы доктор и хотите пригласить на консультацию?

Нет. Потому что там НЕТ варианта ok. Там есть reply, noreply и stop. И падало оно ИМЕННО потому, что возвращался неподходящий по типу результат.

Ок. Был не прав.

anatoly
()
Ответ на: комментарий от wakuwaku

Подскажи сам, пожалуйста, какую метку для тебя добавить.

«динамические опердени» ему подойдет.

Pavval ★★★★★
()
Ответ на: комментарий от Miguel

Но у меня тоже историй есть.

Есть либа, внутрях написана на сплюсе, но интерфейс к ней - на С. К этой самой либе есть прослойка, в виде сплюсового хидера и спп файла, который, как выяснилось позже, реализует точно такой же интерфейс, как и внутренние классы либы. Спп файл прослойки делает загрузку либы dlopen’ом, а потом dlsym’ом вытаскивает указатели на ф-ии и вызывает их потом в методах.

И вот, значит, компилишь ты этот хидер с спп файликом в проект, запускаешь значит конструктор любого из классов из хидера и всё падает. Так, чего там на дебагер показывает? Ух ты! Конструктор вызывает ф-ию, которая вызывает конструктор, которая вызывает ф-ию, которая вызывает конструктор … и так пока не стековерфлоу. И все это лишь из-за совпадения названий классов внутри либы и в хидере. Названий грёбаных классов! Названий Грёбаный Классов!

Я на это потратил неделю копания с дебагером в нутрях либы, которую не писал. Потом засунул все классы в хидере в неймспейс и всё заработало.

И вот теперь скажи мне, как мне в этом случае помогла бы статическая типизация? Если какие-то чумовые ребята наваяли всё на указателях на воиды (производительность, кококо!) как тебе поможет статическая типизация? Ну и где Pavval, который кричал про то, что есть хорошие и годные библиотеки на все случаи жизни?

Я не спорю, твой случай - наглядный пример нужности статической типизации, потому-что в одном конкретно взятом случае она бы помогла, но пойми - я ругаю спп за то, что эту идею сплюсмены извратили до невозможности. Они кричат про высокоуровневый универсальный язык, но при этом прячут голову в песок, когда им говорят о тормозутости шаред петеров. Они тут же отвечают „мы умеем указатели“ и начинают творить падучее и неюзабельное гуано, которому никакая статическая типизация не поможет - только костёр. Они говорят, что всё написано на сплюсе - игры там, броузеры. Но что такое современные игры? Что такое современные броузеры? Где же обещанная „производительность“?

Можно ещё сказать вот что. Вот допустим определил я enum {reply, norelpy, stop}. Как мне это экспортировать из либы? Как вообще экспортировать классы и типы? Никак. Нужны костыли в виде пимплов или пихать шаблоны в хидера и распространять с исходниками аля буст. И это значит универсальность? Гибкость?

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

Ну и где Pavval, который кричал про то, что есть хорошие и годные библиотеки на все случаи жизни?

Я тут, солнышко:) А еще есть и плохие и негодные либы на все случаи жизни.

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

В духе „я пишу хелоуворд

int main()
{
 char *s;
 memcpy(s, "hello world\n", 12);
 printf(s);
 return 0;
}
но программа падает почему-то. Подскажите решение.“? Адекватный пример?)

nanoolinux ★★★★
()
Ответ на: комментарий от anatoly

Интересно, а как эта строчка будет выглядить в списке экспортируемых ф-й шареной библиотеки например? Или в каком виде она будет лежать в .а файле?

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

Если какие-то чумовые ребята наваяли всё на указателях на воиды (производительность, кококо!) как тебе поможет статическая типизация?

Ну, очевидно, она поможет тем, что не будет позволять делать «указатели на войды».

Статическая типизация в варианте C++, к сожалению, очень слаба, и от таких вещей не защищает. Это означает ровно одно: нужна более сильная статическая типизация.

Впрочем, твоя история вызывает известные сомнения. Если у либы сишный интерфейс, то что там внутрях — по идее, не должно влиять никак.

Другой вопрос, если ты подключил либу исходниками. Тогда да, проблемы понятные — но не надо тогда говорить про интерфейс на C.

но пойми - я ругаю спп за то, что эту идею сплюсмены извратили до невозможности

Вообще-то, ты не ругал плюсы, а восхвалял эрланг. См. Как в C++11 принято разделять реализацию и объявление шаблонных классов (комментарий) — если бы ты там ругал плюсы, я бы тебя только поддержал, плюсы полное говно; но ты явно считаешь, что падение эрланговского процесса — это так, ничего особенного. Я на это и отреагировал.

Miguel ★★★★★
()
Ответ на: комментарий от nanoolinux

Не менее интересно, как сильно будет тормозить Крайзис, если его написать на Эрланге.

anatoly
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.