Метапрограмирането на шаблони по-бързо ли е от еквивалентния C код?

Метапрограмирането на шаблона по-бързо ли е от еквивалентния C код? (Говоря за производителността по време на изпълнение) :)


person n00ki3    schedule 25.07.2009    source източник
comment
Това беше гласувано против? Сериозно? Изглежда ми напълно добър въпрос. (въпреки че заглавието и основната част на въпроса изглежда задават два различни въпроса, може би е добра идея да изясните кой от тях ви интересува)   -  person jalf    schedule 25.07.2009
comment
Искате да кажете, че е по-бързо да се програмира? или искаш да кажеш, че се изпълнява по-бързо? Вашият въпрос е двусмислен и изглежда, че получаваме отговори и на двата въпроса, което е малко объркващо.   -  person Dipstick    schedule 25.07.2009
comment
Трябва да покажете двата кода и тогава можем да ги разсъждаваме. Просто не можете да зададете този въпрос такъв, какъвто е, няма смисъл.   -  person Johannes Schaub - litb    schedule 25.07.2009
comment
Нямам примери, но го имам предвид като цяло. Значи бързото сортиране е по-бързо от бързото сортиране в C. Или: Изграждането на дърво е по-бързо, отколкото в C... и така нататък.   -  person n00ki3    schedule 26.07.2009
comment
Мисля, че има смисъл, както е. Разбира се, отговорите трябва да са много по-общи, отколкото ако беше попитал за две специфични реализации на даден алгоритм, но ако беше направил това, бихме могли просто да го измерим така или иначе. За C програмист, любопитен защо C++ хората продължават да говорят за метапрограмиране на шаблони, мисля, че това е добър въпрос. Има някои общи характеристики на производителността на генеричното програмиране и шаблонното метапрограмиране, които ги правят полезни   -  person jalf    schedule 26.07.2009
comment
@n00ki3: Мисля, че не си разбрал какво представлява TMP. Сортирането обикновено не се извършва с помощта на TMP, въпреки че TMP получава (допълнителни) ускорения от същите функции на C++, които ускоряват сортирането (както вече беше обяснено от други две).   -  person sbi    schedule 26.07.2009


Отговори (8)


Първо, отказ от отговорност: това, за което мисля, че питате, е не само шаблонно метапрограмиране, но и общо програмиране. Двете понятия са тясно свързани и няма точна дефиниция какво обхваща всяко от тях. Но накратко, шаблонното метапрограмиране по същество е писане на програма, използваща шаблони, която се оценява по време на компилиране. (което го прави напълно безплатно по време на изпълнение. Нищо не се случва. Стойността (или по-често тип) вече е изчислена от компилатора и е достъпна като константа (или константна променлива, или enum), или като typedef вложен в клас (ако сте го използвали за "изчисляване" на тип).

Генеричното програмиране използва шаблони и, когато е необходимо, шаблонно метапрограмиране, за да създаде общ код, който работи по същия начин (и без загуба на производителност), с всички и всеки тип. Ще използвам примери и за двете по-долу.

Обща употреба на метапрограмиране на шаблони е да се даде възможност на типовете да се използват в генерично програмиране, дори ако не са предназначени за това.

Тъй като метапрограмирането на шаблони технически се извършва изцяло по време на компилация, вашият въпрос е малко по-подходящ за генерично програмиране, което все още се извършва по време на изпълнение, но е ефективно, защото може да бъде специализирано за точните типове, с които се използва по време на компилация.

Така или иначе...


Зависи как дефинирате "еквивалентния C код".

Номерът на шаблонното метапрограмиране (или генеричното програмиране като цяло) е, че позволява много изчисления да бъдат преместени във времето за компилиране и позволява гъвкав, параметризиран код, който е също толкова ефективен, колкото твърдо кодираните стойности.

Кодът, показан тук, например изчислява число в редицата на фибоначи по време на компилация.

C++ кодът 'unsigned long fib11 = fibonacci<11uL>::value' разчита на шаблонната метапрограма, дефинирана в тази връзка, и е толкова ефективен, колкото C кода 'unsigned long fib11 = 89uL'. Шаблоните се оценяват по време на компилиране, като се получава константа, която може да бъде присвоена на променлива. Така че по време на изпълнение кодът всъщност е идентичен с обикновено присвояване.

Така че, ако това е "еквивалентният C код", производителността е същата. Ако еквивалентният C код е "програма, която може да изчислява произволни числа на Фибоначи, приложени за намиране на 11-то число в последователността", тогава C версията ще бъде много по-бавна, защото трябва да бъде внедрена като функция, която изчислява стойността по време на изпълнение. Но това е „еквивалентен C код“ в смисъл, че това е C програма, която проявява същата гъвкавост (това не е просто твърдо кодирана константа, а действителна функция, която може да върне всяко число в последователност на фибоначи).

Разбира се, това често не е полезно. Но това е до голяма степен каноничният пример за метапрограмиране на шаблони.

По-реалистичен пример за генерично програмиране е сортирането.

В C имате стандартната библиотечна функция qsort, която приема масив и указател на функция за сравнение. Извикването на този указател на функция не може да бъде вградено (освен в тривиални случаи), защото по време на компилиране не се знае коя функция ще бъде извикана.

Разбира се, алтернативата е ръчно написана функция за сортиране, предназначена за вашия конкретен тип данни.

В C++ еквивалентът е шаблонът на функцията std::sort. Той също изисква компаратор, но вместо това да е функционален указател, той е функционален обект, изглеждащ така:

struct MyComp {
  bool operator()(const MyType& lhs, const MyType& rhs) {
     // return true if lhs < rhs, however this operation is defined for MyType objects
  }
};

и това може да бъде вградено. На функцията std::sort се предава шаблонен аргумент, така че тя знае точния тип на сравнителния инструмент и така знае, че сравнителната функция не е просто указател на неизвестна функция, а MyComp::operator().

Крайният резултат е, че C++ функцията std::sort е точно толкова ефективна, колкото ръчно кодираната ви реализация в C на същия алгоритъм за сортиране.

Така че отново, ако това е "еквивалентният C код", тогава производителността е същата. Но ако „еквивалентният C код“ е „обобщена функция за сортиране, която може да се приложи към всеки тип и позволява дефинирани от потребителя компаратори“, тогава генеричната програмна версия в C++ е много по-ефективна.

Това наистина е трикът. Генеричното програмиране и шаблонното метапрограмиране не са „по-бързи от C“. Те са методи за постигане на общ, многократно използваем код, който е толкова бърз, колкото ръчно кодиран и твърдо кодиран C

Това е начин да получите най-доброто от двата свята. Ефективността на твърдо кодираните алгоритми и гъвкавостта и повторното използване на общите, параметризирани такива.

person jalf    schedule 25.07.2009
comment
jalf Използвах примера за сортиране в моя отговор, така че +1 за C++ warrior :D - person AraK; 25.07.2009
comment
Хм, мисля, че има огромна разлика между общото програмиране и TMP, но разбирам, че сте въвели примера с GP, за да изразите мнението си. Все пак бих пропуснал намек, че компараторът не е TMP. - person sbi; 26.07.2009
comment
справедлива точка. Добавих малко обяснение в началото какво представляват GP и TMP и споменах, че примерът за сортиране обикновено се счита за GP, но мисля, че ще го оставя така. - person jalf; 26.07.2009

Шаблонното метапрограмиране (TMP) се „изпълнява“ по време на компилиране, така че всъщност не се сравняват ябълки с ябълки, когато се сравнява с нормален C/C++ код.

Но ако имате нещо, оценено от TMP, тогава изобщо няма разходи за изпълнение.

person Michael Burr    schedule 25.07.2009

Ако имате предвид многократно използваем код, тогава да без съмнение. Метапрограмирането е превъзходен начин за създаване на библиотеки, а не на клиентски код. Клиентският код не е общ, той е написан да прави конкретни неща.

Например, погледнете qsort от C стандартна библиотека и C++ стандартен sort. Ето как работи qsort:

int compare(const void* a, const void* b)
{
    return (*(int*)a > *(int*)b);
}

int main()
{
    int data[5] = {5, 4, 3, 2, 1};

    qsort(data, 5, sizeof(int), compare);
}

Сега погледнете сортирай:

struct compare
{
    bool operator()(int a, int b)
    { return a < b; }
};

int main()
{
    int data[5] = {5, 4, 3, 2, 1};
    std::sort(data, data+5, compare());
}

Сортирането е по-чисто, по-безопасно и по-ефективно, защото функцията за сравнение е вградена в сортирането. Това е ползата от метапрограмирането според мен, вие пишете общ код, но компилаторът произвежда код като ръчно кодирания !


Друго място, където намирам метапрограмирането за много красиво, е когато пишете библиотека като boost::spirit или boost::xpressive, с spirit можете да напишете EBNF в C++ и да оставите компилацията да провери EBNF синтаксиса вместо вас и с xpressive можете да пишете регулярен израз и да оставите компилатора да провери и синтаксиса на регулярния израз вместо вас!


Не съм сигурен дали питащият има предвид под TMP изчисляване на стойности по време на компилация. Това е пример, който написах с помощта на boost :)

unsigned long greatestCommonDivisor = boost::math::static_gcd<25657, 54887524>::value;

Каквото и да правите със C, не можете да имитирате горния код, основно трябва да го изчислите на ръка, след което да присвоите резултата на greatestCommonDivisor!

person AraK    schedule 25.07.2009
comment
Е, това е изчисляване на типа по време на компилиране :) не е задължително да са числени изчисления. - person AraK; 25.07.2009
comment
питащият не дефинира какво има предвид под шаблонно метапрограмиране и еквивалентен C код, така че трябваше да гадае така или иначе. - person Johannes Schaub - litb; 25.07.2009
comment
Когато специализирате шаблон, компилаторът изчислява типа на аргумента, той не е числов, а е изчисление :) - person AraK; 25.07.2009
comment
Не мисля, че ОП възнамеряваше напълно строго разграничение между генерично програмиране и шаблонно метапрограмиране. Мисля, че сортираните примери отговарят на това, което той искаше да знае, независимо от точната терминология. +1 - person jalf; 26.07.2009
comment
А, сега разбирам. :) Но все още твърдя, че типът не се изчислява :) Знае типа. - person GManNickG; 26.07.2009
comment
Не знам дали бих нарекъл Spirit красив пример за метапрограмиране. Очарователно, сигурно, впечатляващо, определено, но... Може би малко над ръба. :) - person jalf; 26.07.2009
comment
Знам, че синтаксисът на EBNF става малко гаден, но наистина как можете да го направите на всеки друг език;) - person AraK; 26.07.2009
comment
Не можете, но повечето хора също биха казали, че не трябва. Просто казвам, че това може би не е най-добрият реален пример за TMP, който е полезен. :Д - person jalf; 26.07.2009

Отговорът е, че зависи.

Метапрограмирането на шаблон може да се използва за лесно писане на рекурсивни езикови парсери и те могат да бъдат неефективни в сравнение с внимателно изработена C програма или базирана на таблица реализация (напр. flex/bison/yacc).

От друга страна, можете да пишете метапрограми, които генерират разгънати цикли, което може да бъде по-ефективно от по-конвенционална C реализация, която използва цикли.

Основното предимство е, че метапрограмите позволяват на програмиста да прави повече с по-малко код.

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

person Jeff Leonard    schedule 25.07.2009

Метапрограмирането на шаблон може да се разглежда като изпълнение по време на компилация.

Времето за компилиране ще отнеме повече време за компилиране на вашия код, тъй като той трябва да компилира и след това да изпълни шаблоните, да генерира код и след това да компилира отново.

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

person Sean A.O. Harney    schedule 25.07.2009

Работих по проект, в който друг програмист беше изпробвал метапрограмиране. Беше ужасно. Беше пълно главоболие. Аз съм средностатистически програмист с много опит в C++ и опитът да измисля какво, по дяволите, се опитват да направят, отне много повече време, отколкото ако го бяха написали направо в началото.

Изтощен съм от C++ MetaProgramming заради този опит.

Аз съм твърдо убеден, че най-добрият код е най-лесен за четене от средностатистически програмист. Четливостта на софтуера е приоритет №1. Мога да накарам всичко да работи, използвайки всеки език... но умението е да го направя четимо и лесно работещо за следващия човек в проекта. C++ MetaProgramming не успява да премине теста.

person Kieveli    schedule 25.07.2009
comment
Може би проблемът е бил, че вашият сътрудник не е документирал достатъчно какво прави неговият код за метапрограмиране? Или може би просто не беше много добър в писането на разбираем код. Във всеки случай не съм сигурен, че е честно да осъждам цялата техника въз основа на един опит с една кодова база. - person Jeremy Friesner; 25.07.2009
comment
Съгласен съм с Джереми. Може би вашият колега не беше добър в писането на кода или не го правеше чисто, но не мисля, че това, че не го четете, го прави лошо. Може би беше написано добре и просто ви трябваше повече опит с шаблоните? - person GManNickG; 25.07.2009
comment
Може би самият код не се е поддал на метапрограмиране! - person AraK; 25.07.2009
comment
Мда, това е природата на звяра с C++: всеки път, когато се добави нова функция към езика, мъниците злоупотребяват с нея, докато не се появи нещо по-блестящо, което да привлече вниманието им. Както когато езикът се появи за първи път и те претоварваха операторите наляво и надясно. - person Ken Keenan; 25.07.2009
comment
Тъй като очевидно е злоупотреба да се използва обща, ефективна функция за сортиране, вместо да се налага или да използвате неефективна, или да кодирате ръчно за всеки един тип, който искате да сортирате. Да, виждам как това е злоупотреба и прави кода по-труден за четене... ‹/sarcasm› Разбира се, може да се злоупотребява и разбира се може да създаде нечетлив код. Но също така може да опрости много код, който иначе би бил бъркотия за гледане. - person jalf; 26.07.2009

Метапрограмирането на шаблони не ви дава никакви магически сили по отношение на производителността. По същество това е много сложен препроцесор; винаги можете да напишете еквивалента на C или C++, просто може да ви отнеме много време.

person Nathan Monteleone    schedule 20.08.2009

Не мисля, че има шум, но ясен и прост отговор относно шаблоните се дава от ЧЗВ за C++: https://isocpp.org/wiki/faq/templates#overview-templates

Относно първоначалния въпрос: не може да се отговори, тъй като тези неща не са сравними.

person Community    schedule 25.07.2009