Jump to content

C++ mindfuck ar templatēm un namespacēm


binary
 Share

Recommended Posts

Nav ne jautājums, nekas - drīzāk "piektdienas spams" par mindfucku, kādā var iegrābties, ja nepārzin standartus no A līdz Z :D
 

namespace ns
{
   struct s1 {};
   void foo(s1* value);
}

template <class T>
void foobar()
{
   T value;
   ns::foo(&value);
}

namespace ns
{
   struct s2 {};
   void foo(s2* value);
}

void test()
{
    foobar<ns::s1>();
    foobar<ns::s2>();
}

Kompilējas? Studijā - jā, GCC - nē. Kuram taisnība? Kā runā, GCC šoreiz taisnība :) Bet vajag, lai kompilējas, turklāt nemainot koda secību.

 

Risinājumi?
1) Aizvākt namespaces. Pilnībā. Kompilējas? Jā. Drīkstat minēt, kāpēc :) Šoreiz gan tāds risinājums nederēs.

2) Pamainīt templatē "ns:foo()" izsaukumu ar "using ns::foo; foo()". Kompilējas? Jā. Drīkstat minēt, kāpēc tā :)

 

Vēl lielākai jautrībai var piemest "void foo(int*)" deklarāciju pēc templeita un mēģināt darīt "foobar<int>()". Kompilējas? Protams, ka nē. Neatkarīgi no visādiem usingiem. Drīkstat minēt, kāpēc tā :)

 

Un pavisam lielai jautrībai var izcelt otro foo deklarāciju ārpus namespaces kā "void foo(ns::s2* value);" Kompilējas? Protams, ka nē. Kam interesanti, var paspēlēties ar dažādiem argumentiem. Kam pavisam interesanti, var doties palasīt standartus, lai neuzrautos uz šitādiem pārsteigumiem… Citādi faktiski šitādi "dienas wtf" nāk gaismā pēc tam, kad vairākas dienas ir vienkārši notriektas ar domām no sērijas "nu vot kāpēc šitais nestrādā?!"

Labots - binary
Link to comment
Share on other sites

Nu nav gan, reāli tas viss apmēram šādā secībā sastājas pēc visādām includēm. Tāpēc jau ari nevaru mainīt koda secību. Tas, kas ir redzams pirmajā postā, ir vairāku dienu garumā ļooooti stipri apgraizīts kods, kurā reproducēta oriģinālā problēma.

Link to comment
Share on other sites

ieleja, principā jā. Jāpiebilst gan, ka tiek kompilēts kā objekta fails (t.i., outputā ir nevis executablis, bet objekts).

 

MarisO, to, ka tāds variants kompilējas, es jau pierakstīju. Tiesa, arī ne visos gadījumos - atkarīgs no tā, kas kur deklarēts (t.i., kur deklarēta funkcija un kur - mainīgā value tips). Mērķis? Šim konkrētajam kodam - reproducēt problēmu, ar kuru vairākas dienas cīnījos produkcijas kodā, tādējādi nosakot konkrētu iemeslu, kāpēc produkcijas kods nekompilējās.

Labots - binary
Link to comment
Share on other sites

varbūt var izskaidrot c++ nespeciālistiem kas tur darās?

 

1)  kāpēc nekompilējas ns::foo(&value); bet vajag using ...?   vai tāpēc, ka using ietekmē kodu,  kas seko pēc tā ?

2)  vienkārši foo(&value);  kompilējas (clang++) un izsauc pareizo f-ju , ar s1 un s2 !

 

#include <iostream>
namespace ns
{
   struct s1 {};
   void foo(s1* value) { std::cout << "S1-";};
}
template <class T>
void foobar()
{
   T value;
   foo(&value);
}
namespace ns
{
   struct s2 {};
   void foo(s2* value) { std::cout << "S2-"; };
}
int main()
{
    foobar<ns::s1>();
    foobar<ns::s2>();
}
Labots - MarisO
Link to comment
Share on other sites

Nav tā ka foobar definicijā tiek explicitly inicializēta viena konkrēta funkcijas versija no namespeisa kas tajā brīdī ir definēta? Atiecīgi lietojot using tiek ņemts viss ns kā tāds.

Link to comment
Share on other sites

MarisO, nē, nevar izskaidrot ;) Tur tad jāsēž un jālasa standartus (vai arī tos jau jāpārzina).

 

Vienkāršā valodā - tas, vai kompilējas vai nē, atkarīgs no tā, kā/kur konkrētajā gadījumā tiek meklēta templeitā izsaucamā funkcija, atkarībā no tā, kur deklarēts templeita arguments.

 

Jeasus, tā gluži nebūs gan.

 

 

P.S. Papildus jautrību tam visam piešķir tas, ka studija to visu sagremo bez jelkādām acīmredzamām problēmām :D

Labots - binary
Link to comment
Share on other sites

"void foo(int*)" deklarāciju pēc templeita

 

call to function 'foo' that is neither visible in the template definition nor found by argument-dependent lookup
 
visi, kas nekodē iekš c++,  "slavē jēzu", ka viņiem neliek kodēt c++  :)
Labots - MarisO
Link to comment
Share on other sites

Inspektors Caps

 

 

nepārzin standartus no A līdz Z

Tas arī ir frankenšteina C++ lielākais mīnuss - to valodu nav iespējams zināt visu. Jā, tas ir mīnuss, pie tam milzīgs!

 

 

 

visi, kas nekodē iekš c++, "slavē jēzu", ka viņiem neliek kodēt c++

Heh, vismaz beidzot kaut kur varu Tev piekrist! :) Pašam šur tur sanāk vieglāk izmantot C++ dēļ COM vai citām bibliotēkām, bet arī tad kodu veidoju pēc iespējas vienkāršāku, tīras klases, līdzīgāk C un pēc iespējas neizmantojot C++ perversijas, lai viss paliktu stingros kārtības rāmjos.

  • Patīk 1
Link to comment
Share on other sites

Inspektors Caps, nu tas attiecas uz jebkuru lielu "platformu" - līdz ko tā kļūst gana liela un funkcionāla, tā to vairs nav iespējams pilnībā pārzināt ne "platformas lietotājiem", ne tās "attīstītājiem". To var kompensēt ar detalizētas, ērti lietojamas un viegli saprotamas dokumentācijas palīdzību. Nu un, protams, ar zinošu nozares speciālistu palīdzību - gan vietējo (kolēģu), gan pa visu pasauli izkaisīto (domājams, vairums te pazīst kaut vai to pašu stackoverflow, kur zinoši ļaudis apgrozās).

 

C++ perversijas ir pat ļoti noderīgas, ja tās pārzina un pielieto tur, kur tās tiešām nepieciešamas. Un ja devam tā ir viena no pamatvalodām, tad tās perversijas, kā izrādās, nav nemaz tik ļoti perversas.

 

Ja par citu valodu lietošanu - ir jomas, kur nav daudz variantu, tikai C un/vai C++. Un šad tad tos pašus nākas lietot ierobežotā veidā, jo ne visas standarta fīčas ir implementētas kompilatoros.


 

 

2) vienkārši foo(&value); kompilējas (clang++) un izsauc pareizo f-ju , ar s1 un s2 !

Vienkārši "foo()" bez jelkādiem "using". Tas ir Koenig lookup (nosaukts par godu Andrew Koenig, lai arī viņš to neieviesa), zināms arī kā argument-dependent [name] lookup. Standartā diezgan samudžināti sarakstīts, bet Nicolai Josuttis (grāmatas The C++ Standard Library: A Tutorial and Reference autors) vienkāršos vārdos to pasaka šādi:

>> You don’t have to qualify the namespace for functions if one or more argument types are defined in the namespace of the function.

Link to comment
Share on other sites

visi, kas nekodē iekš c++, "slavē jēzu", ka viņiem neliek kodēt c++

Jā, grābekļu tur ir ļoti daudz. Te ir ļoti labi izskaidrots, kas ir C++.

Link to comment
Share on other sites

nevertell

Akmanudies, vaimanuvai, programmēšanas valoda ļauj cilvēkam darīt stulbas lietas.

 

Ja vien jūs visu nerakstat ar Haskell, tad jums nav tiesību teikt, ka viena vai otra valoda sūc, kā iemeslu stādot valodas sarežģītību. 

Link to comment
Share on other sites

Nesaprotu, kāpēc tā ir "jautrība". Afaik tas ir visparastākais ADL: https://en.wikipedia.org/wiki/Argument-dependent_name_lookup

Standarta lieta C++'ā, kas tiek izmantota daudz kur un ir jāpārzin. Piemēram, overraidojot std::swap vai operator <</>> std::ostream/std::istream klasēm.

 

Ja ADL šķiet brīnumu lieta, tad nākamais būs SFINAE :)https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error

Un CRTP: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

Labots - bubu
Link to comment
Share on other sites

bubu, tici vai nē, bet ne es, ne kolēģi nezināja, kāpēc pirmajā topikā esošais koda gabals nestrādāja, savukārt pamainot templeita iekšas (un nemainot koda secību), sāka strādāt. Šķiet, man arī šobrīd tas līdz galam nav skaidrs.

Labots - binary
Link to comment
Share on other sites

C++ perversijas ir pat ļoti noderīgas, ja tās pārzina un pielieto tur, kur tās tiešām nepieciešamas.

Pilnīgi nepiekrītu.

Ja tev patīk risināt rēbusus un apdomāt šaha kombinācijas, tad jā.  Bet ja ir vajadzīgs - Get the Job Done un vislabāk ASAP, tad labāk no tām perversijām turēties tālāk. Lielākā daļa tās tāpat nepārzina un ja pielieto, tad tur, kur tās vispār nav nepieciešamas.

Ja valodas izvēle ir tavās rokās un nav tādi faktori, kā kāda neaizvietojama biblene, tad C++ ir pirmais, ko var atmest.

Visu to pašu un vēl labāk var izdarīt ar citiem rīkiem, ir tonnām fantastiska softa sarakstīts citās valodās - VB (tas ir uz 14 Jan 2014 datumu, ja. Wikipedia saka Stable release 6.0 / 1998; 17 years ago), Object pascal/Lazarus/Delphi pamatīga bibleņu un koda čupa sākot jau ar D5 laikiem. Literatūras kalni. Kāda jēga tērēt laiku, lai apgūtu tās perversijas, tad mācītos pielietot, tad gadiem cīnītos ar atmiņas noplūdēm un citām problēmām.

FPC, piemēram, par visu padomāts - nekādu atmiņas noplūžu vairs (kā vienā zināmā reklāmā), range checking, kompilēšana notiek ļoti ātri - vieni plusi.

Tā ir kā kaut kāda sazvērestība, kas sākās vēl BCC 5.5 laikos, kad C++ reklamēja uz katra stūra. Dažreiz šķiet, ka tāda intervija ar Stroustrupa kungu reiz tomēr bija.

 

Kamēr vieni nodarbojas ar C++ mindf#ck, tikmēr citi raksta ātru, lieliski strādājošu softu, kurš bija nepieciešams jau vakar un ir vajadzīgs rīt vēlams līdz pulksten 12-tiem un lai strādātu kā pulkstens.

 

jums nav tiesību teikt, ka viena vai otra valoda sūc, kā iemeslu stādot valodas sarežģītību.

Kā iemeslu es stādu produktivitāti. Cik ātri un kvalitatīvi ir gatavs strādājošs rezultāts. Labas atsauksmes ir dzirdētas par kādreiz populāro Borland C++ Builder 6, kas principā bija tie paši Delphi ar C++ sintaksi. Ir pozitīvi iepaidi par Qt, kas varētu teikt ir C++ dialekts ar savu moc un savām biblenēm praktiski jebkuram gadījumam sākot ar QString un beidzot ar QWidget.

 

Tā, ka ja runājam par produktivitāti, tad tev nav tiesību man teikt, ka man nav tiesību teikt, ka viena valoda ir sūc.

 

Link to comment
Share on other sites

binary: Nē, nu nezināt ir OK. Visi kādreiz kaut ko nezināja. Bet atrodot kaut ko ko nesaproti, vienmēr var pagūglēt un atrast izskaidrojumu. Pat visparastākajā wikipēdijā.

 

Ja pareizi atceros mēs ADL izmantojām divās vietās N projektā. Pirms ieviesām C++11, pēc tam to aizstājām std::enable_if.

Un ja pareizi atceros par vecāku kodu, tad T projektam 5 versijā viss ģenerētais C++ kods ļoti paļāvās uz ADL. Viss bija neimspeisos, bet izsaucot funkcijas (Copy, ...) nevajadzēja tās prefiksot ar neimspeisu - Copy(a, b, c), nevis ns::Copy(a,b,c).

 

@HIGH-Zen: +1

Man pēdējā laikā jau labu laiku šķiet, ka C++ brauc uz  nepareizo pusi. C++11 likās vēl OK (kaut daudz par vēlu), tad tagad ar visiem C++17 un C++2X(sazinkas) ir briesmas. Principā neko daudz vairāk par "C ar klasēm" (+ nelieli labumi) negribas.

Labots - bubu
Link to comment
Share on other sites

HIGH-Zen, ar "get the job done ASAP" nekas nebeidzas, ir projekti, kas ar to tikai sākas. Tādā gadījumā svarīgi ir, lai tas viss būtu arī normāli attīstāms un uzturams turpmākos gadus. Vai tas nozīmē "perversiju" izmantošanu vai nē - tas atkarīgs no konkrētā projekta specifikas.

Tonnām fantastisku softu var būt uzrakstīti da jebkādā valodā (da kaut pitonā vai PHP), bet C un C++ joprojām paliek neaizvietojami uz dažādām eksotiskām platformām, kurām gluži vienkārši nav pieejams ne VB, ne Delphi, ne Python, nedz arī kas cits. Tikai un vienīgi C un C++. Grozies kā gribi, bet tādas platformas bija, ir un būs.

---

bubu, šodien/vakar kā reiz paskatījos - visi Copy u.c. tiek prefixoti ar ns. Nu vismaz tie, kurus skatījos. Nemācēšu teikt, kāpēc tā - uzskatāmības dēļ vai kā cita dēļ. Vēl vairāk - ns ir defains :)

Link to comment
Share on other sites

kurām gluži vienkārši nav pieejams ne VB, ne Delphi, ne Python,

Es jau teiktu, ja ir pieejams C, tad ir pieejams (vai arī ir iespējams) arī Python. Gan uz visādiem mikrokontrolieriem (https://micropython.org/ un https://wiki.python.org/moin/PyMite), gan grub bootloaderī - Python bez OS: 

 

Tagad Tv6 jā, Copy tiek prefiksots. Es to teicu par to kā bija agrāk - Tv4 vai Tv5 laikos.

Labots - bubu
Link to comment
Share on other sites

Izveido kontu, vai pieraksties esošajā, lai komentētu

Jums ir jābūt šī foruma biedram, lai varētu komentēt tēmas

Izveidot jaunu kontu

Piereģistrējies un izveido jaunu kontu, tas būs viegli!

Reģistrēt jaunu kontu

Pierakstīties

Jums jau ir konts? Pierakstieties tajā šeit!

Pierakstīties tagad!
 Share

×
×
  • Izveidot jaunu...