සැකිලි ශීර්ෂ ගොනුවේ පමණක් ක්‍රියාත්මක කළ හැක්කේ ඇයි?


1794

C ++ සම්මත පුස්තකාලයෙන් උපුටා ගැනීම : නිබන්ධනයක් සහ අත්පොතක් :

මේ මොහොතේ සැකිලි භාවිතා කළ හැකි එකම අතේ ගෙන යා හැකි ක්‍රමය වන්නේ පේළිගත කිරීමේ ශ්‍රිත භාවිතා කරමින් ඒවා ශීර්ෂ ලිපිගොනු තුළ ක්‍රියාත්මක කිරීමයි.

ඇයි මේ?

(පැහැදිලි කිරීම: ශීර්ෂ ලිපිගොනු එකම අතේ ගෙන යා හැකි විසඳුම නොවේ. නමුත් ඒවා වඩාත් පහසු අතේ ගෙන යා හැකි විසඳුම වේ.)


14
සියලුම අච්චු ක්‍රියාකාරී අර්ථ දැක්වීම් ශීර්ෂ ගොනුවට දැමීම බොහෝ විට ඒවා භාවිතා කිරීමට වඩාත් පහසුම ක්‍රමය බව සත්‍යයක් වුවත්, එම උපුටා දැක්වීමේදී “පේළිගත කිරීම” කරන්නේ කුමක්ද යන්න තවමත් පැහැදිලි නැත. ඒ සඳහා පේළිගත කිරීමේ කාර්යයන් භාවිතා කිරීමේ අවශ්‍යතාවයක් නොමැත. "ඉන්ලයින්" ට මේ සමඟ කිසිම සම්බන්ධයක් නැත.
AnT

8
පොත යල්පැන ඇත.
ජෙරාඩ්

2
අච්චුවක් බයිට් කේතයට සම්පාදනය කළ හැකි ශ්‍රිතයක් මෙන් නොවේ. එය එවැනි ශ්‍රිතයක් ජනනය කිරීමේ රටාවක් පමණි. ඔබ අච්චුවක් තනිවම * .cpp ගොනුවකට දැමුවහොත්, සම්පාදනය කිරීමට කිසිවක් නැත. එපමණක් නොව, පැහැදිලි ක්ෂණිකකරණය ඇත්ත වශයෙන්ම අච්චුවක් නොවේ, නමුත් * .obj ගොනුවේ අවසන් වන අච්චුවෙන් ශ්‍රිතයක් සෑදීමේ ආරම්භක ලක්ෂ්‍යය.
dgrat

6
මේ නිසා C ++ හි අච්චු සංකල්පය
අක්‍රීය

Answers:


1574

Caveat: ක්‍රියාත්මක කිරීම ශීර්ෂ ගොනුවට දැමීම අවශ්‍ය නොවේ , මෙම පිළිතුර අවසානයේ විකල්ප විසඳුම බලන්න.

කෙසේ වෙතත්, ඔබේ කේතය අසමත් වීමට හේතුව, අච්චුවක් ස්ථාපනය කිරීමේදී, සම්පාදකයා විසින් ලබා දී ඇති අච්චු තර්කය සමඟ නව පන්තියක් නිර්මාණය කිරීමයි. උදාහරණයක් වශයෙන්:

template<typename T>
struct Foo
{
    T bar;
    void doSomething(T param) {/* do stuff using T */}
};

// somewhere in a .cpp
Foo<int> f; 

මෙම පේළිය කියවන විට, සම්පාදකයා නව පන්තියක් නිර්මාණය කරයි (අපි එය අමතමු FooInt), එය පහත සඳහන් දේට සමාන වේ:

struct FooInt
{
    int bar;
    void doSomething(int param) {/* do stuff using int */}
}

එහි ප්‍රති the ලයක් වශයෙන්, සම්පාදකයාට ක්‍රමවේදයන් ක්‍රියාත්මක කිරීමට ප්‍රවේශය තිබිය යුතුය, ඒවා අච්චු තර්කය සමඟ ක්ෂණික කිරීමට (මෙම අවස්ථාවේ දී int). මෙම ක්‍රියාත්මක කිරීම් ශීර්ෂයේ නොතිබුනේ නම්, ඒවාට ප්‍රවේශ විය නොහැකි අතර, එම නිසා සම්පාදකයාට අච්චුව ක්ෂණිකව ක්‍රියාත්මක කිරීමට නොහැකි වනු ඇත.

මේ සඳහා පොදු විසඳුමක් වන්නේ අච්චු ප්‍රකාශය ශීර්ෂ ගොනුවක ලිවීම, ඉන්පසු පන්තිය ක්‍රියාත්මක කිරීමේ ගොනුවක ක්‍රියාත්මක කිරීම (උදාහරණයක් ලෙස .tpp), සහ ශීර්ෂයේ අවසානයේ මෙම ක්‍රියාත්මක කිරීමේ ගොනුව ඇතුළත් කිරීම.

Foo.h

template <typename T>
struct Foo
{
    void doSomething(T param);
};

#include "Foo.tpp"

Foo.tpp

template <typename T>
void Foo<T>::doSomething(T param)
{
    //implementation
}

මේ ආකාරයෙන්, ක්‍රියාත්මක කිරීම තවමත් ප්‍රකාශනයෙන් වෙන් කර ඇති නමුත් සම්පාදකයාට ප්‍රවේශ විය හැකිය.

විකල්ප විසඳුමක්

තවත් විසඳුමක් නම් ක්‍රියාත්මක කිරීම වෙන්ව තබා ගැනීම සහ ඔබට අවශ්‍ය සියලුම අච්චු අවස්ථා පැහැදිලිව ක්ෂණිකව තහවුරු කිරීමයි:

Foo.h

// no implementation
template <typename T> struct Foo { ... };

Foo.cpp

// implementation of Foo's methods

// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float

මගේ පැහැදිලි කිරීම ප්‍රමාණවත් තරම් පැහැදිලි නැතිනම්, ඔබට මෙම විෂය පිළිබඳ C ++ සුපර්-නිති අසන ප්‍රශ්න දෙස බැලිය හැකිය .


96
ඇත්ත වශයෙන්ම පැහැදිලි ක්ෂණිකකරණය .cpp ගොනුවක තිබිය යුතු අතර එය ශීර්ෂයට වඩා Foo හි සියලුම සාමාජික ක්‍රියාකාරකම් සඳහා අර්ථ දැක්වීම් වලට ප්‍රවේශය ඇත.
මාන්කර්ස්

11
"සම්පාදකයාට ක්‍රමවේදයන් ක්‍රියාත්මක කිරීමට ප්‍රවේශය තිබිය යුතුය, ඒවා අච්චු තර්කය සමඟ ක්ෂණිකව තහවුරු කිරීම සඳහා (මෙම අවස්ථාවේ දී int). මෙම ක්‍රියාත්මක කිරීම් ශීර්ෂයේ නොතිබුනේ නම්, ඒවාට ප්‍රවේශ විය නොහැක" නමුත් ක්‍රියාත්මක කිරීමේදී .cpp ගොනුව සම්පාදකයාට ප්‍රවේශ විය නොහැකිද? සම්පාදකයෙකුට .cpp තොරතුරු වෙත ප්‍රවේශ විය හැකිය, එය වෙනත් ඒවා .obj ගොනු බවට පත් කරන්නේ කෙසේද? සංස්කරණය කරන්න: මෙම ප්‍රශ්නයට පිළිතුර මෙම පිළිතුරේ සපයා ඇති සබැඳියේ ඇත ...
xcrypt

32
මෙම
ලිපියේ

6
Ab ගැබ්සන්: ව්‍යුහයන් සහ පන්ති සමාන වන්නේ පන්ති සඳහා පෙරනිමි ප්‍රවේශ විකරණකාරකය “පුද්ගලික” වන අතර එය ව්‍යුහයන් සඳහා පොදු වේ. මෙම ප්‍රශ්නය දෙස බැලීමෙන් ඔබට ඉගෙන ගත හැකි තවත් කුඩා වෙනස්කම් කිහිපයක් තිබේ .
ලූක් ටුරේල්

3
ප්‍රශ්නය පදනම් වී ඇත්තේ ව්‍යාජ පරිශ්‍රයක් මත බව පැහැදිලි කිරීම සඳහා මම මෙම පිළිතුර ආරම්භයේදීම වාක්‍යයක් එක් කළෙමි. කවුරුහරි ඇසුවොත් "ඇයි X ඇත්ත?" ඇත්ත වශයෙන්ම X සත්‍ය නොවන විට, අපි එම උපකල්පනය ඉක්මනින් ප්‍රතික්ෂේප කළ යුතුය.
ආරොන් මැක්ඩයිඩ්

253

එයට හේතුව වෙනම සම්පාදනයක අවශ්‍යතාවය සහ සැකිලි ක්ෂණික ශෛලීය බහුමාපකය වන බැවිනි.

පැහැදිලි කිරීමක් සඳහා කොන්ක්‍රීට් වලට ටිකක් සමීප වීමට ඉඩ දෙමු. මට පහත ලිපිගොනු ඇති බව පවසන්න:

  • foo.h
    • හි අතුරු මුහුණත ප්‍රකාශ කරයි class MyClass<T>
  • foo.cpp
    • ක්‍රියාත්මක කිරීම අර්ථ දක්වයි class MyClass<T>
  • bar.cpp
    • භාවිතා කරයි MyClass<int>

මම සම්පාදනය කිරීමට හැකි විය යුතුය වෙනම සම්පාදනය කිරිමේ ක්රම foo.cpp ස්වාධීනව සිට bar.cpp . එක් එක් සම්පාදන ඒකකයේ විශ්ලේෂණය, ප්‍රශස්තිකරණය සහ කේත උත්පාදනය යන සියලු වෙහෙස මහන්සි වී සම්පාදකයා සම්පූර්ණයෙන්ම ස්වාධීනව කරයි; අපට සම්පූර්ණ වැඩසටහන් විශ්ලේෂණය කිරීමට අවශ්‍ය නැත. මුළු වැඩසටහනම එකවර හැසිරවිය යුත්තේ සම්බන්ධකය පමණි, සහ සම්බන්ධකයේ කාර්යය සැලකිය යුතු ලෙස පහසුය.

bar.cpp පවා මම බැදීමකට පවතී කිරීම අවශ්ය නොවේ foo.cpp , නමුත් මම තවමත් සම්බන්ධ කිරීමට හැකි විය යුතුය foo.o මම දැනටමත් සමග එකට සිටි bar.o recompile වෙත යාමකින් තොරව, මම යන්තම් ඉදිරිපත් තියෙනවා foo .cpp . foo.cpp ගතික පුස්තකාලයකට සම්පාදනය කර, foo.cpp නොමැතිව වෙනත් තැනකට බෙදා හැරිය හැකි අතර , මම foo.cpp ලිවීමෙන් වසර ගණනාවකට පසු ඔවුන් ලියන කේත සමඟ සම්බන්ධ කළ හැකිය .

"Instantiation-style polymorphism" යන්නෙන් අදහස් කරන්නේ අච්චුව MyClass<T>යනු ඕනෑම වටිනාකමක් සඳහා ක්‍රියා කළ හැකි කේතයකට සම්පාදනය කළ හැකි සාමාන්‍ය පන්තියක් නොවන බවයි T. බව C ++ සැකිලි මෙහි අරමුණ කට ආසන්න සමාන ලිවීමට ඇති නොගැනීමයි ආදිය විබෙදන්නෙක්ට හා ඉදිකිරීම් කර්මාන්තකරුවාගේ කටයුතු කිරීමට සූචක සම්මත කිරීමට අවශ්ය බොක්සිං, වැනි පොදුකාර්ය පිරිවැය එකතු වනු ඇත class MyClass_int, class MyClass_floatආදිය, නමුත් තවමත් බව සම්පාදනය කේතය සමඟ අවසන් කිරීමට හැකි විය අපි නම් බොහෝ ලෙස තිබේ , ෙවන් ෙවන් වශෙයන් සෑම අනුවාදය ලියා. එබැවින් අච්චුවක් වචනාර්ථයෙන් අච්චුවකි; පන්ති අච්චුවක් පන්තියක් නොවේ , එය Tඅපට හමු වන සෑම කෙනෙකුටම නව පන්තියක් නිර්මාණය කිරීම සඳහා වූ වට්ටෝරුවකි . අච්චුවක් කේතයට සම්පාදනය කළ නොහැක, අච්චුව ස්ථාපනය කිරීමේ ප්‍රති result ලය පමණක් සම්පාදනය කළ හැකිය.

එබැවින් foo.cpp සම්පාදනය කළ විට , එය අවශ්‍ය බව දැන ගැනීමට සම්පාදකයාට bar.cpp නොපෙනේMyClass<int> . එයට අච්චුව දැකිය හැකිය MyClass<T>, නමුත් ඒ සඳහා කේත විමෝචනය කළ නොහැක (එය අච්චුවක් මිස පන්තියක් නොවේ). Bar.cpp සම්පාදනය කළ විට , එය නිර්මාණය කිරීමට අවශ්‍ය බව සම්පාදකයාට දැකිය හැකිය MyClass<int>, නමුත් එයට අච්චුව දැකිය නොහැක MyClass<T>( foo.h හි එහි අතුරු මුහුණත පමණි ) එබැවින් එය නිර්මාණය කළ නොහැක.

Foo.cpp විසින්ම භාවිතා කරන්නේ නම්, foo.cppMyClass<int> සම්පාදනය කිරීමේදී ඒ සඳහා කේතය ජනනය වනු ඇත , එබැවින් bar.o foo.o සමඟ සම්බන්ධ වූ විට ඒවා සම්බන්ධ කර ක්‍රියා කළ හැකිය. තනි අච්චුවක් ලිවීමෙන් .cpp ගොනුවක් තුළ සීමිත අච්චු සැකසුම් මාලාවක් ක්‍රියාත්මක කිරීමට ඉඩ දීම සඳහා අපට එම කරුණ භාවිතා කළ හැකිය. නමුත් අච්චුව අච්චුවක් ලෙස භාවිතා කිරීමට හා එය කැමති ඕනෑම වර්ගයක ක්ෂණිකව ස්ථාපනය කිරීමට bar.cpp ට ක්‍රමයක් නොමැත ; එයට භාවිතා කළ හැක්කේ foo.cpp හි කතුවරයා සැපයීමට සිතූ සැකසූ පන්තියේ පෙර පැවති අනුවාදයන් පමණි .

අච්චුවක් සම්පාදනය කිරීමේදී සම්පාදකයා "සියලු සංස්කරණ ජනනය කළ යුතුය", කිසි විටෙකත් භාවිතා නොකරන ඒවා සම්බන්ධ කිරීමේදී පෙරහන් නොකෙරේ යැයි ඔබට සිතෙනු ඇත. විශාල පොදු පිරිවැය සහ එවැනි ප්‍රවේශයකට මුහුණ දීමට සිදුවන දුෂ්කරතා හැරුණු විට, දර්ශක සහ අරා වැනි “ටයිප් මෝඩිෆයර්” විශේෂාංග මඟින් ගොඩනඟන ලද වර්ගවලට පවා අසීමිත වර්ග ගණනක් බිහි කිරීමට ඉඩ සලසයි, මම දැන් මගේ වැඩසටහන දීර් when කරන විට කුමක් සිදුවේද? එකතු කිරීමෙන්:

  • baz.cpp
    • ප්‍රකාශ කිරීම සහ ක්‍රියාත්මක කිරීම class BazPrivateසහ භාවිතා කිරීමMyClass<BazPrivate>

අප හෝ හැර මෙය ක්‍රියාත්මක විය හැකි ක්‍රමයක් නොමැත

  1. වැඩසටහනේ වෙනත් ඕනෑම ගොනුවක් වෙනස් කරන සෑම අවස්ථාවකම foo.cpp නැවත සකස් කළ යුතුය .MyClass<T>
  2. බව අවශ්ය baz.cpp පූර්ණ ආකෘතියකි (ශීර්ෂක ඇතුලත් හරහා හැකි) MyClass<T>සම්පාදකවරයා ජනනය කළ හැකි නිසා බව, MyClass<BazPrivate>එම් සම්පාදනය තුළ baz.cpp .

කිසිවෙකු කැමති නැත (1), මන්දයත් සමස්ත වැඩසටහන්-විශ්ලේෂණ සම්පාදක පද්ධති සම්පාදනය කිරීමට සදහටම ගත වන නිසාත්, ප්‍රභව කේත නොමැතිව සම්පාදිත පුස්තකාල බෙදා හැරීමට නොහැකි නිසාත් ය. ඒ නිසා අපට ඒ වෙනුවට (2) ඇත.


51
අවධාරණය කළ උපුටා දැක්වීමක් අච්චුවක් වචනාර්ථයෙන් අච්චුවකි; පන්ති අච්චුවක් පංතියක් නොවේ, එය අපට හමු වන සෑම ටී සඳහාම නව පන්තියක් නිර්මාණය කිරීම සඳහා වූ වට්ටෝරුවකි
v.oddou

මම දැන ගැනීමට කැමතියි, පන්තියේ ශීර්ෂකය හෝ ප්‍රභව ගොනුව හැර වෙනත් තැනකින් පැහැදිලි තොරතුරු ලබා ගත හැකිද? උදාහරණයක් ලෙස, ඒවා main.cpp හි තිබේද?
gromit190

1
Ir බර්ගර් ඔබට සම්පූර්ණ අච්චු ක්‍රියාත්මක කිරීමට ප්‍රවේශය ඇති ඕනෑම ගොනුවකින් එය කළ හැකිය (එය එකම ගොනුවේ ඇති නිසා හෝ ශීර්ෂකය හරහා ඇතුළත් වේ).
බෙන්

11
@ajeh එය වාචාල නොවේ. ප්රශ්නය වන්නේ "ඔබට ශීර්ෂ පා in යක් තුළ සැකිලි ක්රියාත්මක කළ යුත්තේ ඇයි?", එබැවින් C ++ භාෂාව මෙම අවශ්යතාවයට හේතු වන තාක්ෂණික තේරීම් මම පැහැදිලි කළෙමි. මම මගේ පිළිතුර ලිවීමට පෙර අනෙක් අය දැනටමත් සම්පූර්ණ විසඳුම් ලබා නොදෙන විසඳුම් ලබා දී ඇත. ප්‍රශ්නයේ “ඇයි” ​​කෝණය පිළිබඳ පූර්ණ සාකච්ඡාවකින් එම පිළිතුරු සම්පුර්ණ වනු ඇතැයි මට හැඟුණි.
බෙන්

1
මේ ආකාරයට සිතන්න ... ඔබ සැකිලි භාවිතා නොකරන්නේ නම් (ඔබට අවශ්‍ය දේ කාර්යක්ෂමව කේත කිරීමට), ඔබ ඉදිරිපත් කරන්නේ කෙසේ හෝ එම පන්තියේ අනුවාද කිහිපයක් පමණි. එබැවින් ඔබට විකල්ප 3 ක් ඇත. 1). සැකිලි භාවිතා නොකරන්න. (අනෙකුත් සියලුම පන්ති / කාර්යයන් මෙන්, අනෙක් අයට වර්ග වෙනස් කළ නොහැකි යැයි කිසිවෙකු ගණන් ගන්නේ නැත) 2). සැකිලි භාවිතා කරන්න, සහ ඔවුන්ට භාවිතා කළ හැකි වර්ග මොනවාදැයි ලේඛනගත කරන්න. 3). සම්පූර්ණ ක්‍රියාත්මක කිරීම (ප්‍රභව) ප්‍රසාද දීමනාව ඔවුන්ට ලබා දෙන්න 4). ඔබේ පංතියෙන් වෙනත් අයෙකුගෙන් අච්චුවක් සෑදීමට අවශ්‍ය නම් ඔවුන්ට සම්පූර්ණ ප්‍රභවය ලබා දෙන්න;)
පුඩ්ල්

250

මෙහි නිවැරදි පිළිතුරු ඕනෑ තරම් ඇත, නමුත් මට මෙය එකතු කිරීමට අවශ්‍ය විය (සම්පූර්ණත්වය සඳහා):

ඔබ, ක්‍රියාත්මක කිරීමේ සීපීපී ගොනුවේ පතුලේ, අච්චුව භාවිතා කරන සියලු වර්ගයන් පැහැදිලි ලෙස ක්ෂණිකව සිදු කරන්නේ නම්, සම්බන්ධකයට සුපුරුදු පරිදි ඒවා සොයාගත හැකිය.

සංස්කරණය කරන්න: පැහැදිලි අච්චු ස්ථාපනය සඳහා උදාහරණයක් එකතු කිරීම. අච්චුව නිර්වචනය කිරීමෙන් පසුව භාවිතා වන අතර සියලුම සාමාජික කාර්යයන් අර්ථ දක්වා ඇත.

template class vector<int>;

මෙය පංතිය සහ එහි සියලුම සාමාජික ක්‍රියාකාරකම් (පමණක්) ක්ෂණිකව (සහ සම්බන්ධකයට ලබා දෙනු ඇත). අච්චු කාර්යයන් සඳහා සමාන සින්ටැක්ස් ක්‍රියා කරයි, එබැවින් ඔබට සාමාජික නොවන ක්‍රියාකරු අධි බරක් තිබේ නම් ඒවා සඳහාද ඔබ එයම කළ යුතුය.

ඉහත උදාහරණය තරමක් නිෂ් less extern template class vector<int>ල බැවින් ශීර්ෂයන් තුළ දෛශිකය සම්පූර්ණයෙන් අර්ථ දක්වා ඇත. දෛශිකය භාවිතා කරන අනෙකුත් (1000?) ලිපිගොනු වල එය ස්ථාපනය කිරීමෙන් වළක්වා ගැනීම සඳහා පොදු ඇතුළත් ගොනුවක් (පෙර සැකසූ ශීර්ෂකය?) භාවිතා කරන විට හැර .


52
අහ්. හොඳ පිළිතුරක්, නමුත් සැබෑ පිරිසිදු විසඳුමක් නැත. අච්චුවක් සඳහා විය හැකි සියලු වර්ග ලැයිස්තුගත කිරීම අච්චුවක් විය යුතු දේ සමඟ නොපෙනේ.
ජිමිනියන්

7
මෙය බොහෝ අවස්ථාවන්හිදී හොඳ විය හැකි නමුත් සාමාන්‍යයෙන් අච්චුවේ අරමුණ බිඳ දමයි, එයින් අදහස් කරන්නේ typeඒවා අතින් ලැයිස්තුගත නොකර ඕනෑම එකක් සමඟ පන්තිය භාවිතා කිරීමට ඔබට ඉඩ සලසයි .
ටොමේ සැටෝ - මොනිකා

7
vectorකන්ටේනරයක් සහජයෙන්ම “සියලු” වර්ග ඉලක්ක කර ඇති නිසා එය හොඳ උදාහරණයක් නොවේ. නමුත් බොහෝ විට සිදුවන්නේ ඔබ විශේෂිත වර්ග සමූහයක් සඳහා පමණක් සැකසෙන අච්චු නිර්මාණය කිරීමයි, උදාහරණයක් ලෙස සංඛ්‍යාත්මක වර්ග: int8_t, int16_t, int32_t, uint8_t, uint16_t, ආදිය. මේ අවස්ථාවේ දී, අච්චුවක් භාවිතා කිරීම අර්ථවත් කරයි. , නමුත් සමස්ත වර්ග සමූහය සඳහාම ඒවා පැහැදිලිවම ස්ථාපනය කිරීම ද කළ හැකි අතර, මගේ මතය අනුව නිර්දේශ කරනු ලැබේ.
UncleZeiv

අච්චුව නිර්වචනය කිරීමෙන් පසුව භාවිතා වන අතර, "සහ සියලුම සාමාජික කාර්යයන් අර්ථ දක්වා ඇත". ස්තූතියි!
Vitt Volt

1
මට යමක් මග හැරී ඇති බවක් මට හැඟේ… මම වර්ග දෙකක් සඳහා පැහැදිලි ක්ෂණික තොරතුරු පන්තියේ .cppගොනුවට දැමූ අතර, ඉන්ස්ටෙන්ටේෂන් දෙක වෙනත් .cppලිපිගොනු වලින් යොමු කරනු ලැබේ , සාමාජිකයන් සොයාගත නොහැකි සම්බන්ධක දෝෂය මට තවමත් ලැබේ.
ඕර්ෆිෂ්

83

ආකෘති සැබවින්ම වස්තු කේතයට සම්පාදනය කිරීමට පෙර සම්පාදකයා විසින් ක්ෂණිකව කළ යුතුය . මෙම ක්ෂණිකකරණය සාක්ෂාත් කරගත හැක්කේ අච්චු තර්ක දන්නේ නම් පමණි. අච්චු ශ්‍රිතයක් ප්‍රකාශයට පත් කර a.h, අර්ථ දක්වා ඇති a.cppසහ භාවිතා කරන අවස්ථාවක් දැන් සිතන්න b.cpp. a.cppසම්පාදනය කරන විට , එළඹෙන සම්පාදනය b.cppසඳහා අච්චුවේ නිදසුනක් අවශ්‍ය වනු ඇති බව නොදනී . තවත් ශීර්ෂ සහ මූලාශ්‍ර ලිපිගොනු සඳහා, තත්වය ඉක්මනින් වඩාත් සංකීර්ණ විය හැකිය.

අච්චුවේ සියලු භාවිතයන් සඳහා "ඉදිරිය දෙස බැලීමට" සම්පාදකයින් වඩාත් දක්ෂ ලෙස කළ හැකි යැයි කෙනෙකුට තර්ක කළ හැකිය, නමුත් පුනරාවර්තන හෝ වෙනත් ආකාරයකින් සංකීර්ණ අවස්ථා නිර්මාණය කිරීම අපහසු නොවන බව මට විශ්වාසයි. AFAIK, සම්පාදකයින් එවැනි පෙනුමක් ලබා නොදේ. ඇන්ටන් පෙන්වා දුන් පරිදි, සමහර සම්පාදකයින් අච්චු ස්ථාපනය පිළිබඳ පැහැදිලි අපනයන ප්‍රකාශයන්ට සහාය දක්වයි, නමුත් සියලු සම්පාදකයින් එයට සහාය නොදක්වයි (තවමත්?).


1
"අපනයනය" සම්මතයි, නමුත් එය ක්‍රියාත්මක කිරීම අසීරු බැවින් සම්පාදක කණ්ඩායම් බොහොමයක් තවමත් සිදු කර නොමැත.
vava

5
අපනයනය මඟින් ප්‍රභව අනාවරණය කිරීමේ අවශ්‍යතාවය ඉවත් නොකරයි, එසේම එය සම්පාදක පරායත්තතාවයන් අඩු නොකරයි, ඒ සඳහා සම්පාදක තනන්නන්ගෙන් විශාල උත්සාහයක් අවශ්‍ය වේ. එබැවින් හර්බ් සූටර් විසින්ම අපනයන ගැන අමතක කරන්නැයි සම්පාදකයින්ගෙන් ඉල්ලා සිටියේය. ආයෝජනය කිරීමට අවශ්‍ය කාලය වෙනත් තැනක ගත කිරීම වඩා හොඳ වනු ඇත ...
පීටර්

2
එබැවින් අපනයනය 'තවම' ක්‍රියාත්මක නොවන බව මම නොසිතමි. අනෙක් අය කොපමණ කාලයක් ගතවී ඇත්ද සහ කොපමණ ප්‍රමාණයක් උපයා ඇත්දැයි දුටු පසු එය EDG හැර වෙන කිසිවෙකු විසින් සිදු නොකරනු ඇත
පීටර්

3
එය ඔබට උනන්දුවක් දක්වන්නේ නම්, එම පත්‍රය "අපට අපනයනය කළ නොහැක්කේ ඇයි" යනුවෙන් හැඳින්වේ, එය ඔහුගේ බ්ලොග් අඩවියේ ලැයිස්තුගත කර ඇත ( gotw.ca/publications ) නමුත් එහි පීඩීඑෆ් නැත (ඉක්මන් ගූගල් එය හැරවිය යුතුය)
පීටර්

1
හරි, හොඳ උදාහරණයකට සහ පැහැදිලි කිරීමකට ස්තූතියි. මෙන්න මගේ ප්‍රශ්නය: සම්පාදකයාට අච්චුව කැඳවනු ලැබුවේ කොහෙන්දැයි සොයාගත නොහැකි අතර, අර්ථ දැක්වීමේ ගොනුව සම්පාදනය කිරීමට පෙර එම ගොනු සම්පාදනය කළ යුත්තේ ඇයි? මට හිතාගන්න පුළුවන් ඒක සරල අවස්ථාවක කරන්න පුළුවන් කියලා ... අන්තර් පරායත්තතාවයන් ඇණවුම ඉතා ඉක්මණින් අවුල් කරයිද?
ව්ලැඩ්

63

ඇත්තෙන්ම, සම්මත C ++ 11 පෙර අර්ථ exportබව ඉඟි පද ඇත එය ශීර්ෂ ගොනුවේ සැකිලි ප්රකාශ කිරීම හා වෙනත් ස්ථානයක ක්රියාත්මක කිරීමට හැකියාව කරන්න.

ජනප්‍රිය සම්පාදකයින් කිසිවෙකු මෙම මූල පදය ක්‍රියාත්මක කළේ නැත. මා දන්නා එකම දෙය කොමාඕ සී ++ සම්පාදකයා විසින් භාවිතා කරන එඩිසන් ඩිසයින් ග Group ප් විසින් ලියන ලද ෆ්‍රොන්ටෙන්ඩ් ය. අනෙක් සියල්ලම ඔබට ශීර්ෂ ලිපිගොනු වල සැකිලි ලිවීමට අවශ්‍ය විය, මන්ද යත් සම්පාදකයාට නිසි ස්ථාපනය සඳහා අච්චු අර්ථ දැක්වීම අවශ්‍ය වන බැවිනි (අනෙක් අය දැනටමත් පෙන්වා දී ඇති පරිදි).

එහි ප්‍රති As ලයක් ලෙස, exportC ++ 11 සමඟ සැකිලි වල අංගය ඉවත් කිරීමට ISO C ++ සම්මත කමිටුව තීරණය කළේය .


6
... සහ වසර කිහිපයකට පසු, ඇත්ත වශයෙන්ම අපට ලබා දෙන්නේ කුමක් ද යන්නත්, නොකළ යුතු දේත් මම අවසාන වශයෙන් තේරුම් ගතිමි ... දැන් මම ඊඩීජී ජනතාව සමඟ මුළු හදින්ම එකඟ වෙමි: එය බොහෝ මිනිසුන් (මා විසින්ම ගෙන එනු නොලැබේ ' ඇතුළත් කර ඇත) එය සිතනු ඇති අතර C ++ ප්‍රමිතිය එය නොමැතිව වඩා හොඳය. export
දේව්සොලර්

5
E ඩෙව්සොලර්: මෙම ලිපිය දේශපාලන, පුනරාවර්තන හා නරක ලෙස ලියා ඇත. එය සාමාන්‍ය සම්මත ගද්‍යයක් නොවේ. පිටු දස දහස් ගණනක් පුරා එකම දේ මෙන් 3 ගුණයක් කියමින් අනවශ්‍ය ලෙස දිගු හා කම්මැලි ය. නමුත් අපනයනය අපනයනය නොවන බව මට දැන් දන්වා සිටිමි. ඒක හොඳ ඉන්ටෙල් එකක්!
v.oddou

1
. v.oddou: හොඳ සංවර්ධකයෙකු සහ හොඳ තාක්ෂණික ලේඛකයෙක් වෙනම කුසලතා දෙකකි. සමහරුන්ට දෙකම කළ හැකිය, බොහෝ දෙනෙකුට නොහැකිය. ;-)
DevSolar

1
paper v.oddou පුවත්පත නරක ලෙස ලියා නැත, එය වැරදි තොරතුරු ය. එය යථාර්ථයේ භ්‍රමණයකි: අපනයන සඳහා සැබවින්ම අතිශයින්ම ප්‍රබල තර්ක මිශ්‍ර වී ඇත්තේ ඒවා අපනයනයට විරුද්ධ යැයි හැඟෙන අයුරිනි. “අපනයනය ඉදිරියේ ප්‍රමිතියේ ODR සම්බන්ධිත සිදුරු ගණනාවක් සොයා ගැනීම. අපනයනය කිරීමට පෙර, ODR උල්ලං lations නයන් සම්පාදකයා විසින් හඳුනාගත යුතු නැත. විවිධ පරිවර්තන ඒකක වලින් අභ්‍යන්තර දත්ත ව්‍යුහයන් ඒකාබද්ධ කිරීමට ඔබට අවශ්‍ය නිසා දැන් එය අවශ්‍ය වන අතර ඒවා ඇත්ත වශයෙන්ම විවිධ දේ නියෝජනය කරන්නේ නම් ඔබට ඒවා ඒකාබද්ධ කළ නොහැක, එබැවින් ඔබ පරීක්ෂා කිරීම කළ යුතුය. ”
කුතුහලයෙන්

1
E ඩෙව්සොලර් අපනයනයට එරෙහිව නඩුවක් තවමත් පුවත්පතේ නොපෙනේ. ( අපනයනය සඳහා නඩුවක් මම දකිමි .)
කුතුහලයෙන්

34

සම්මත C ++ ට එවැනි අවශ්‍යතාවයක් නොතිබුණද, සමහර සම්පාදකයින්ට ඔවුන් භාවිතා කරන සෑම පරිවර්තන ඒකකයකම සියලුම ක්‍රියාකාරීත්වයන් සහ පන්ති සැකිලි ලබා දිය යුතුය. ඇත්ත වශයෙන්ම, එම සම්පාදකයින් සඳහා, අච්චු ක්‍රියාකාරිත්වයේ සිරුරු ශීර්ෂ ගොනුවකින් ලබා දිය යුතුය. පුනරාවර්තනය කිරීම සඳහා: එයින් අදහස් කරන්නේ .cpp ගොනු වැනි ශීර්ෂ නොවන ලිපිගොනු වල අර්ථ දැක්වීමට එම සම්පාදකයින් ඉඩ නොදෙන බවයි

මෙම ගැටළුව අවම කිරීම සඳහා අපනයන මූල පදයක් ඇත, නමුත් එය අතේ ගෙන යා හැකි තැනකට ආසන්න නැත.


"Inline" යතුර සමඟ .cpp ගොනුවේ මට ඒවා ක්‍රියාත්මක කළ නොහැක්කේ ඇයි?
MainID

2
ඔබට පුළුවන්, ඔබට "පේළිගත" කිරීමට පවා අවශ්‍ය නැත. නමුත් ඔබට ඒවා එම සීපීපී ගොනුවේ පමණක් භාවිතා කළ හැකි අතර වෙන කොතැනකවත් නැත.
vava

10
මෙය වඩාත් නිවැරදි පිළිතුර වන අතර, “එයින් අදහස් කරන්නේ එම සම්පාදකයින් විසින් .cpp ගොනු වැනි ශීර්ෂ නොවන ලිපිගොනු වල අර්ථ දැක්වීමට ඉඩ නොදෙන” බවයි.
කක්ෂයේ සැහැල්ලු ධාවන තරඟ

28

සැකිලි ශීර්ෂයන්හි භාවිතා කළ යුතුය, මන්ද යත්, සම්පාදකයාට කේතයේ විවිධ අනුවාදයන් ක්ෂණිකව අවශ්‍ය වන අතර, අච්චු පරාමිතීන් සඳහා ලබා දී ඇති / අඩු කළ පරාමිතීන් මත පදනම්ව ය. අච්චුවක් සෘජුවම කේතය නියෝජනය නොකරන බව මතක තබා ගන්න, නමුත් එම කේතයේ අනුවාද කිහිපයක් සඳහා අච්චුවක්. ඔබ .cppගොනුවක අච්චු නොවන ශ්‍රිතයක් සම්පාදනය කරන විට , ඔබ සංයුක්ත ශ්‍රිතයක් / පන්තියක් සම්පාදනය කරයි. සැකිලි සඳහා මෙය එසේ නොවේ, විවිධ වර්ග සමඟ ක්ෂණිකව ක්‍රියාත්මක කළ හැකිය, එනම්, අච්චු පරාමිතීන් කොන්ක්‍රීට් වර්ග වෙනුවට ආදේශ කිරීමේදී කොන්ක්‍රීට් කේතය විමෝචනය කළ යුතුය.

exportවෙනම සම්පාදනය සඳහා භාවිතා කිරීමට අදහස් කරන යතුරුපදය සහිත අංගයක් තිබුණි . මෙම exportලක්ෂණය ප්රතික්ෂේප කරයි C++11සහ AFAIK, එකම එක සම්පාදක එය ක්රියාත්මක කර ඇත. ඔබ ප්‍රයෝජනයට නොගත යුතුය export. වෙනමම සම්පාදනය කළ නොහැකි C++හෝ C++11සමහර විට C++17, සංකල්ප මඟින් එය සිදු කරන්නේ නම්, අපට වෙනම සම්පාදනය කිරීමේ ක්‍රමයක් තිබිය හැකිය.

වෙනම සම්පාදනයක් ලබා ගැනීම සඳහා, වෙනම අච්චු ශරීර පරීක්ෂා කිරීමක් කළ යුතුය. සංකල්ප සමඟ විසඳුමක් ලබා ගත හැකි බව පෙනේ. ප්‍රමිති කමිටු රැස්වීමේදී මෑතකදී ඉදිරිපත් කරන ලද මෙම පත්‍රය දෙස බලන්න . පරිශීලක කේතයේ ඇති අච්චු කේතය සඳහා ඔබ තවමත් කේත ක්ෂණික කළ යුතු බැවින් මෙය එකම අවශ්‍යතාවයක් නොවන බව මම සිතමි.

සැකිලි සඳහා වෙනමම සම්පාදනය කිරීමේ ගැටළුව එය දැනට ක්‍රියාත්මක වෙමින් පවතින මොඩියුල වෙත සංක්‍රමණය වීමත් සමඟ පැන නගින ගැටළුවක් බව මම අනුමාන කරමි.


16

ඉහත හොඳ පැහැදිලි කිරීම් ඕනෑ තරම් තිබුණත්, සැකිලි ශීර්ෂයට සහ ශරීරයට වෙන් කිරීමට මට ප්‍රායෝගික ක්‍රමයක් නොමැත.
මගේ ප්‍රධාන අවධානය යොමු වන්නේ මා එහි අර්ථ දැක්වීම වෙනස් කරන විට, සියලු අච්චු භාවිතා කරන්නන් නැවත සකස් කිරීම වළක්වා ගැනීමයි.
අච්චු ශරීරයේ සියලුම අච්චු ස්ථාපනය කිරීම මට ශක්‍ය විසඳුමක් නොවේ, මන්ද එහි භාවිතය සහ අච්චු භාවිතා කරන්නාට එය වෙනස් කිරීමට අයිතියක් නොමැති නම් අච්චු කතුවරයා සියල්ල නොදන්නා බැවිනි.
මම පහත දැක්වෙන ප්‍රවේශය ගත් අතර එය පැරණි සම්පාදකයින් සඳහාද ක්‍රියා කරයි (gcc 4.3.4, aCC A.03.13).

සෑම අච්චු භාවිතය සඳහාම එහි ශීර්ෂ ගොනුවේ යතුරු ලියනය කර ඇත (යූඑම්එල් ආකෘතියෙන් ජනනය වේ). එහි සිරුරේ ක්ෂණිකකරණය අඩංගු වේ (එය අවසන් වන්නේ සම්බන්ධිත පුස්තකාලයක ය).
අච්චුවේ සෑම පරිශීලකයෙකුටම එම ශීර්ෂ ගොනුව ඇතුළත් වන අතර යතුරු ලියනය භාවිතා කරයි.

ක්‍රමානුකූල උදාහරණයක්:

MyTemplate.h:

#ifndef MyTemplate_h
#define MyTemplate_h 1

template <class T>
class MyTemplate
{
public:
  MyTemplate(const T& rt);
  void dump();
  T t;
};

#endif

MyTemplate.cpp:

#include "MyTemplate.h"
#include <iostream>

template <class T>
MyTemplate<T>::MyTemplate(const T& rt)
: t(rt)
{
}

template <class T>
void MyTemplate<T>::dump()
{
  cerr << t << endl;
}

MyInstantiatedTemplate.h:

#ifndef MyInstantiatedTemplate_h
#define MyInstantiatedTemplate_h 1
#include "MyTemplate.h"

typedef MyTemplate< int > MyInstantiatedTemplate;

#endif

MyInstantiatedTemplate.cpp:

#include "MyTemplate.cpp"

template class MyTemplate< int >;

main.cpp:

#include "MyInstantiatedTemplate.h"

int main()
{
  MyInstantiatedTemplate m(100);
  m.dump();
  return 0;
}

මේ ආකාරයට නැවත සැකසීමට අවශ්‍ය වන්නේ අච්චු ස්ථාපනය කිරීම් පමණි, සියලු අච්චු භාවිතා කරන්නන් (සහ පරායත්තයන්) නොවේ.


1
MyInstantiatedTemplate.hගොනුව සහ එකතු කළ MyInstantiatedTemplateවර්ගය හැරුණු විට මම මෙම ප්‍රවේශයට කැමතියි . ඔබ එය භාවිතා නොකරන්නේ නම් එය ටිකක් පිරිසිදුයි, ඉමෝ. මෙය පෙන්වන වෙනත් ප්‍රශ්නයකට මගේ පිළිතුර පරීක්ෂා කරන්න: stackoverflow.com/a/41292751/4612476
කැමරන් ටැක්ලින්ඩ්

මෙය ලෝක දෙකෙන් හොඳම දේ ගනී. මෙම පිළිතුර ඉහළ අගයක් ගනු ඇතැයි මම ප්‍රාර්ථනා කරමි! එකම අදහස තරමක් පිරිසිදු ලෙස ක්‍රියාත්මක කිරීම සඳහා ඉහත සබැඳිය බලන්න.
වර්මර්

15

අච්චු පංති ක්‍රම ක්‍රියාත්මක කිරීම නිර්වචනය කිරීමට වඩාත්ම අතේ ගෙන යා හැකි ක්‍රමය වන්නේ අච්චු පන්ති අර්ථ දැක්වීම තුළ ඒවා නිර්වචනය කිරීමයි.

template < typename ... >
class MyClass
{

    int myMethod()
    {
       // Not just declaration. Add method implementation here
    }
};

8

මෙහි සැලකිය යුතු දෙයක් එක් කිරීමට. ක්‍රියාකාරී සැකිලි නොමැති විට ක්‍රියාත්මක කිරීමේ ගොනුවේ සැකසූ පන්තියක ක්‍රම නිර්වචනය කළ හැකිය.


myQueue.hpp:

template <class T> 
class QueueA {
    int size;
    ...
public:
    template <class T> T dequeue() {
       // implementation here
    }

    bool isEmpty();

    ...
}    

myQueue.cpp:

// implementation of regular methods goes like this:
template <class T> bool QueueA<T>::isEmpty() {
    return this->size == 0;
}


main()
{
    QueueA<char> Q;

    ...
}

2
සැබෑ මිනිසා සඳහා ??? එය සත්‍ය නම් ඔබේ පිළිතුර නිවැරදි එකක් ලෙස පරික්ෂා කළ යුතුය.
මයිකල් IV

හොඳයි, එය ක්‍රියා නොකරයි. අවම වශයෙන් MSVC 2019 දී, අච්චු පන්තියේ සාමාජික ශ්‍රිතයක් සඳහා නොවිසඳුනු බාහිර සංකේතයක් ලබා ගැනීම.
මයිකල් IV

පරීක්ෂා කිරීමට මට MSVC 2019 නොමැත. මෙය C ++ ප්‍රමිතියෙන් අවසර දෙනු ලැබේ. දැන්, MSVC සෑම විටම නීති රීති පිළිපැදීම ගැන කුප්‍රකටය. ඔබ දැනටමත් නොමැති නම්, ව්‍යාපෘති සැකසීම් -> සී / සී ++ -> භාෂාව -> අනුකූලතා ප්‍රකාරය -> ඔව් (අවසර-) උත්සාහ කරන්න.
නිකොස්

1
මෙම නිශ්චිත උදාහරණය ක්‍රියාත්මක වන නමුත් ඔබට isEmptyවෙනත් පරිවර්තන ඒකකයකින් ඇමතිය නොහැක myQueue.cpp...
එම්එම්

7

සැලකිලිමත් වන්නේ .h. එය භාවිතා කරන සියලුම .cpp මොඩියුලවල කොටසක් ලෙස .h සම්පාදනය කිරීමෙන් නිපදවන අමතර සම්පාදන කාලය සහ ද්විමය ප්‍රමාණයේ පිපිරීමක් නම්, බොහෝ අවස්ථාවන්හිදී ඔබට කළ හැකි වන්නේ අච්චු පන්තිය සැකසූ නොවන මූලික පන්තියකින් පැවතීමයි. අතුරු මුහුණතේ වර්ගය මත රඳා නොපවතින කොටස් වන අතර, එම මූලික පන්තියට .cpp ගොනුවේ එය ක්‍රියාත්මක කළ හැකිය.


2
මෙම ප්‍රතිචාරය තව තවත් වෙනස් කළ යුතුය. මම " ස්වාධීනව " ඔබේම ප්‍රවේශය සොයාගත් අතර එය දැනටමත් වෙනත් අයෙකු භාවිතා කර ඇති බව විශේෂයෙන් සොයමින් සිටියෙමි, මන්ද එය නිල රටාවක්ද සහ එයට නමක් තිබේද යන්න මට කුතුහලයක් ඇත. මගේ ප්‍රවේශය නම්, මට ක්‍රියාත්මක කිරීමට class XBaseඅවශ්‍ය ඕනෑම තැනක ක්‍රියාත්මක කිරීම template class X, වර්ගය මත රඳා පවතින කොටස් Xසහ ඉතිරි සියල්ල ඇතුළත් කිරීමයි XBase.
ෆේබියෝ ඒ.

6

එය හරියටම නිවැරදි වන්නේ සම්පාදකයාට එය වෙන් කිරීම සඳහා කුමන වර්ගයක් දැයි දැන ගත යුතු බැවිනි. එබැවින් අච්චු පංති, කාර්යයන්, එනූම්ස් යනාදිය පොදු හෝ පුස්තකාලයක (ස්ථිතික හෝ ගතික) කොටසක් බවට පත් කිරීමට නම් ශීර්ෂ ගොනුවේ ද ක්‍රියාත්මක කළ යුතුය. වේ. සම්පාදකයා නොදන්නේ නම් වර්ගය එය සම්පාදනය කළ නොහැක. .Net එයට හැකි වන්නේ සියලු වස්තු වස්තු පන්තියෙන් උපුටා ගත් බැවිනි. මෙය නොවේ .නෙට්.


5
"ශීර්ෂ ලිපිගොනු සම්පාදනය කර නැත" - එය විස්තර කිරීමේ ඇත්තෙන්ම අමුතු ක්‍රමයකි. ශීර්ෂ ලිපිගොනු "c / cpp" ගොනුවක් මෙන් පරිවර්තන ඒකකයක කොටසක් විය හැකිය.
ෆ්ලෙක්සෝ

2
ඇත්ත වශයෙන්ම, එය සත්‍යයේ පාහේ ප්‍රතිවිරුද්ධ දෙයකි, එනම් ශීර්ෂ ලිපිගොනු බොහෝ විට සම්පාදනය කර ඇති අතර ප්‍රභව ගොනුවක් සාමාන්‍යයෙන් එක් වරක් සම්පාදනය කරනු ලැබේ.
xaxxon

6

සම්පාදක පියවරේදී ඔබ අච්චුවක් භාවිතා කරන විට සම්පාදකයා එක් එක් අච්චු ස්ථාපනය සඳහා කේත ජනනය කරයි. සම්පාදනය හා සම්බන්ධ කිරීමේ ක්‍රියාවලියේදී .cpp ගොනු පිරිසිදු වස්තුවක් හෝ යන්ත්‍ර කේතයක් බවට පරිවර්තනය කර ඇති අතර ඒවායේ යොමු හෝ නිර්වචනය නොකළ සංකේත අඩංගු වේ. මන්දයත් ඔබේ main.cpp හි ඇතුළත් කර ඇති .h ගොනු කිසිදු ක්‍රියාත්මක කිරීමක් නොමැති බැවිනි. ඔබේ අච්චුව සඳහා ක්‍රියාත්මක කිරීම නිර්වචනය කරන වෙනත් වස්තු ගොනුවක් සමඟ සම්බන්ධ වීමට මේවා සුදානම් වන අතර එමඟින් ඔබට සම්පූර්ණ a.out ක්‍රියාත්මක කළ හැකිය.

කෙසේ වෙතත්, ඔබ අර්ථ දක්වන එක් එක් අච්චු ස්ථාපනය සඳහා කේත ජනනය කිරීම සඳහා සැකසුම් පියවරේදී සැකසීමට අවශ්‍ය බැවින්, එහි ශීර්ෂ ගොනුවෙන් වෙනම අච්චුවක් සම්පාදනය කිරීම ක්‍රියා නොකරන්නේ ඒවා සෑම විටම අත හා අත යන බැවිනි. සෑම අච්චුවක්ම ස්ථාපනය කිරීම වචනාර්ථයෙන් මුළුමනින්ම නව පන්තියක් බව. සාමාන්‍ය පන්තියකදී ඔබට .h සහ .cpp වෙන් කළ හැකිය .h යනු එම පන්තියේ සැලැස්මක් වන අතර .cpp යනු අමු ක්‍රියාත්මක කිරීම වන බැවින් ඕනෑම ක්‍රියාත්මක කිරීමේ ලිපිගොනු නිතිපතා සම්පාදනය කර සම්බන්ධ කළ හැකිය. කෙසේ වෙතත් සැකිලි භාවිතා කරයි .h යනු කෙසේද යන්න පිළිබඳ සැලැස්මකි පංතිය බැලිය යුත්තේ වස්තුව අච්චුවක අර්ථය විය යුත්තේ කෙසේද යන්න නොවේ .cpp ගොනුව යනු පන්තියේ අමු නිතිපතා ක්‍රියාත්මක කිරීමක් නොවේ, එය හුදෙක් පන්තියක් සඳහා වන සැලැස්මක් වන අතර .h අච්චු ගොනුවක් ඕනෑම ක්‍රියාවට නැංවිය හැකිය.

එබැවින් සැකිලි කිසි විටෙකත් වෙන වෙනම සම්පාදනය නොකෙරෙන අතර සම්පාදනය කරනු ලබන්නේ ඔබට වෙනත් ප්‍රභව ගොනුවක කොන්ක්‍රීට් ක්ෂණිකතාවයක් ඇති ඕනෑම තැනක පමණි. කෙසේ වෙතත්, කොන්ක්‍රීට් ක්ෂණිකකරණයට අච්චු ගොනුව ක්‍රියාත්මක කිරීම දැන ගැනීමට අවශ්‍ය වේtypename T.h ගොනුවේ කොන්ක්‍රීට් වර්ගයක් භාවිතා කිරීම එම කාර්යය ඉටු නොකරන්නේ .cpp සම්බන්ධ කිරීමට ඇත්තේ කුමක්ද, මට පසුව එය සොයාගත නොහැකි නිසා මතක සැකිලි වියුක්ත බැවින් ඒවා සම්පාදනය කළ නොහැක, එබැවින් මට බල කෙරෙයි සම්පාදනය කිරීම හා සම්බන්ධ කිරීම යනු කුමක්දැයි මම දනිමි, දැන් ක්‍රියාත්මක කිරීම මා සතුව ඇති හෙයින් එය සංවෘත මූලාශ්‍ර ගොනුවට සම්බන්ධ වේ. මූලික වශයෙන්, මම අළුත් අළුත් පන්තියක් නිර්මාණය කිරීමට අවශ්‍ය අච්චුවක් ස්ථාපනය කළ මොහොතේ සිට, මට සම්පාදකයාට දැනුම් දීමක් කළහොත් මිස, මා සපයන වර්ගය භාවිතා කරන විට එම පන්තිය කෙබඳු විය යුතු දැයි මා නොදන්නේ නම් මට එය කළ නොහැක. සැකිලි ක්‍රියාත්මක කිරීම, එබැවින් දැන් සම්පාදකයාට Tමගේ වර්ගය සමඟ ප්‍රතිස්ථාපනය කර සම්පාදනය කිරීමට හා සම්බන්ධ කිරීමට සූදානම් වන කොන්ක්‍රීට් පන්තියක් නිර්මාණය කළ හැකිය.

සාරාංශයක් ලෙස, සැකිලි යනු පන්ති පෙනිය යුතු ආකාරය පිළිබඳ සැලැස්මකි, පන්ති යනු වස්තුවක් පෙනිය යුතු ආකාරය පිළිබඳ සැලැස්මයි. මට ඒවායේ සැකිලි වලින් වෙන් කොට සැකිලි සම්පාදනය කළ නොහැක, මන්ද සම්පාදකයා සම්පාදනය කරන්නේ කොන්ක්‍රීට් වර්ග පමණි, වෙනත් වචන වලින් කිවහොත්, අවම වශයෙන් C ++ හි ඇති සැකිලි පිරිසිදු භාෂා සාරාංශයකි. කථා කිරීම සඳහා අපට වියුක්ත සැකිලි ඉවත් කළ යුතු අතර, අපගේ අච්චු සාරාංශය සාමාන්‍ය පන්ති ගොනුවක් බවට පරිවර්තනය කළ හැකි වන පරිදි ඒවා සමඟ කටයුතු කිරීමට කොන්ක්‍රීට් වර්ගයක් ලබා දීමෙන් අපි එය කරන්නෙමු. .H ගොනුව සහ අච්චුව .cpp ගොනුව වෙන් කිරීම අර්ථ විරහිත ය. සැකිලි වියුක්තකර නිසා නිසා .cpp වෙන් පමණක් .h එම .cpp අපි ඔවුන්ට, ෙවන් ෙවන් වශෙයන් සම්පාදනය නොහැකි නිසා සැකිලි, තනි තනිව සම්පාදනය හා තනි තනිව සම්බන්ධ කළ හැකි එකම වන්නේ එය විකාර සහගත වන අතර,

typename Tසම්පාදනය කිරීමේ පියවරේදී අර්ථය ලබා ගැනීම සම්බන්ධ කිරීමේ පියවර නොවේ, එබැවින් මම සංයුක්තයට Tසම්පූර්ණයෙන්ම අර්ථ විරහිත කොන්ක්‍රීට් අගය වර්ගයක් ලෙස ප්‍රතිස්ථාපනය නොකර අච්චුවක් සම්පාදනය කිරීමට උත්සාහ කළහොත් එහි ප්‍රති object ලයක් ලෙස වස්තු කේතය නිර්මාණය කළ නොහැක. කුමක්දැයි දැන ගන්න T.

Template.cpp ගොනුව සුරකින සහ වෙනත් ප්‍රභවයන්ගෙන් ඒවා සොයාගත් විට ඒවා මාරු කරන තාක්ෂණික වශයෙන් යම් ආකාරයක ක්‍රියාකාරීත්වයක් නිර්මාණය කළ හැකි ය, මම සිතන්නේ ප්‍රමිතියට යතුරු පදයක් exportඇති අතර එය සැකිලි වෙනමම තැබීමට ඉඩ සලසයි. cpp ගොනුව නමුත් බොහෝ සම්පාදකයින් මෙය සැබවින්ම ක්‍රියාත්මක කරයි.

පැත්තක සටහනක්, අච්චු පන්තියක් සඳහා විශේෂීකරණය කරන විට, ඔබට ශීර්ෂය ක්‍රියාත්මක කිරීමෙන් වෙන් කළ හැකිය, මන්ද අර්ථ දැක්වීම අනුව විශේෂීකරණය යනු තනි තනිව සම්පාදනය කර සම්බන්ධ කළ හැකි කොන්ක්‍රීට් වර්ගයක් සඳහා මම විශේෂ izing යෙකු වන බැවිනි.


4

වෙනම ක්‍රියාත්මක කිරීමේ ක්‍රමයක් පහත පරිදි වේ.

//inner_foo.h

template <typename T>
struct Foo
{
    void doSomething(T param);
};


//foo.tpp
#include "inner_foo.h"
template <typename T>
void Foo<T>::doSomething(T param)
{
    //implementation
}


//foo.h
#include <foo.tpp>

//main.cpp
#include <foo.h>

අභ්‍යන්තර_ෆූට ඉදිරි ප්‍රකාශ ඇත. foo.tpp ක්‍රියාත්මක කර ඇති අතර අභ්‍යන්තර_ෆූ.එච්; foo.tpp ඇතුළත් කිරීමට foo.h ට ඇත්තේ එක් පේළියක් පමණි.

සම්පාදනය කරන වේලාවේදී, foo.h හි අන්තර්ගතය foo.tpp වෙත පිටපත් කරනු ලබන අතර පසුව සම්පූර්ණ ගොනුව foo.h වෙත පිටපත් කරනු ලැබේ. මේ ආකාරයෙන්, එක් අතිරේක ගොනුවක් සඳහා හුවමාරුවක් වශයෙන්, සීමාවන් නොමැති අතර නම් කිරීම ස්ථාවර වේ.

මම මෙය කරන්නේ * .tpp හි පන්තියේ ඉදිරි ප්‍රකාශයන් නොපෙනෙන විට කේතය සඳහා ස්ථිතික විශ්ලේෂක බිඳ වැටෙන බැවිනි. ඕනෑම IDE එකක කේත ලිවීමේදී හෝ YouCompleteMe හෝ වෙනත් අය භාවිතා කරන විට මෙය කරදරයකි.


3
s / internal_foo / foo / g සහ foo.h අවසානයේ foo.tpp ඇතුළත් කරන්න. එක් අඩු ගොනුවක්.

1

අච්චු ස්ථාපනය සඳහා "cfront" සහ "borland" ආකෘතිය අතර ඇති වෙළඳාම පිළිබඳව සාකච්ඡා කරන මෙම gcc පිටුව බැලීමට මම යෝජනා කරමි.

https://gcc.gnu.org/onlineocs/gcc-4.6.4/gcc/Template-Instantiation.html

"බෝර්ලන්ඩ්" ආකෘතිය කතුවරයා යෝජනා කරන දෙයට අනුරූප වේ, සම්පූර්ණ අච්චු අර්ථ දැක්වීම සපයයි, සහ දේවල් කිහිප වතාවක් සම්පාදනය කර ඇත.

අත්පොත සහ ස්වයංක්‍රීය අච්චු ස්ථාපනය කිරීම පිළිබඳ පැහැදිලි නිර්දේශ එහි අඩංගු වේ. උදාහරණයක් ලෙස, "-repo" විකල්පය ක්ෂණිකව අවශ්‍ය වන අච්චු එකතු කිරීමට භාවිතා කළ හැකිය. නැතහොත් තවත් විකල්පයක් වන්නේ අතින් සැකිලි ක්ෂණිකව බල කිරීම සඳහා "-fno-implicit-templates" භාවිතා කරමින් ස්වයංක්‍රීය අච්චු ස්ථාපනය අක්‍රීය කිරීමයි.

මගේ අත්දැකීම් අනුව, මම එක් එක් සම්පාදන ඒකකය සඳහා (අච්චු පුස්තකාලයක් භාවිතා කරමින්) ක්ෂණිකව ලබා දෙන සී ++ සම්මත පුස්තකාලය සහ බූස්ට් සැකිලි මත රඳා සිටිමි. මගේ විශාල අච්චු පන්ති සඳහා, මට අවශ්‍ය වර්ග සඳහා වරක් අතින් සැකසුම් ක්ෂණිකව සිදු කරමි.

මෙය මගේ ප්‍රවේශය වන්නේ මා වැඩකරන වැඩසටහනක් සපයන නිසා මිස වෙනත් වැඩසටහන් සඳහා භාවිතා කිරීමට අච්චු පුස්තකාලයක් නොවන බැවිනි. පොතේ කතුවරයා වන ජොසුටිස්, අච්චු පුස්තකාලවල බොහෝ දේ කරයි.

වේගය ගැන මා සැබවින්ම කනස්සල්ලට පත්ව සිටී නම්, මම පෙර සැකසූ ශීර්ෂයන් https://gcc.gnu.org/onlineocs/gcc/Precompiled-Headers.html භාවිතා කර ගවේෂණය කරනු ඇතැයි සිතමි.

එය බොහෝ සම්පාදකයින්ගේ සහාය ලබා ගනී. කෙසේ වෙතත්, අච්චු ශීර්ෂ ලිපිගොනු සමඟ පෙර සැකසූ ශීර්ෂයන් දුෂ්කර වනු ඇතැයි මම සිතමි.


-2

ශීර්ෂ ලිපිගොනු වල ප්‍රකාශන සහ අර්ථ දැක්වීම් දෙකම ලිවීම හොඳ අදහසක් වීමට තවත් හේතුවක් වන්නේ කියවීමේ හැකියාවයි. Utility.h හි එවැනි අච්චු ශ්‍රිතයක් ඇතැයි සිතමු:

template <class T>
T min(T const& one, T const& theOther);

සහ Utility.cpp හි:

#include "Utility.h"
template <class T>
T min(T const& one, T const& other)
{
    return one < other ? one : other;
}

මේ සඳහා සෑම ටී පන්තියකටම ක්‍රියාකරුට වඩා අඩු (<) ක්‍රියාත්මක කිරීම අවශ්‍ය වේ. ඔබ "<" ක්‍රියාත්මක නොකළ පන්ති අවස්ථා දෙකක් සංසන්දනය කරන විට එය සම්පාදක දෝෂයක් ඇති කරයි.

එබැවින් ඔබ අච්චු ප්‍රකාශනය සහ අර්ථ දැක්වීම වෙන් කරන්නේ නම්, මෙම API එක ඔබේ පන්තිවල භාවිතා කිරීම සඳහා ඔබට මෙම අච්චුවේ ඇතුළත හා පිටත බැලීමට ශීර්ෂ ගොනුව පමණක් කියවිය නොහැක, නමුත් සම්පාදකයා ඔබට මෙහි කියනු ඇත කුමන ක්‍රියාකරු අභිබවා යා යුතුද යන්න.


-7

.Cpp ගොනුවකට වඩා .template ගොනුවක් තුළ ඔබේ අච්චු පන්තිය සැබවින්ම අර්ථ දැක්විය හැකිය. ඔබට එය අර්ථ දැක්විය හැක්කේ ශීර්ෂ ගොනුවක් තුළ පමණක් යැයි කවුරුන් පැවසුවත් එය වැරදිය. මෙය c ++ 98 දක්වාම ක්‍රියාත්මක වන දෙයකි.

ඔබේ .template ගොනුව c ++ ගොනුවක් ලෙස ඔබේ සම්පාදකයාට සැලකීමට අමතක නොකරන්න.

ගතික අරා පන්තියක් සඳහා මෙන්න මේ සඳහා උදාහරණයකි.

#ifndef dynarray_h
#define dynarray_h

#include <iostream>

template <class T>
class DynArray{
    int capacity_;
    int size_;
    T* data;
public:
    explicit DynArray(int size = 0, int capacity=2);
    DynArray(const DynArray& d1);
    ~DynArray();
    T& operator[]( const int index);
    void operator=(const DynArray<T>& d1);
    int size();

    int capacity();
    void clear();

    void push_back(int n);

    void pop_back();
    T& at(const int n);
    T& back();
    T& front();
};

#include "dynarray.template" // this is how you get the header file

#endif

දැන් ඔබ තුළ .template ගොනුව ඔබ සාමාන්‍යයෙන් කරන ආකාරයට ඔබේ කාර්යයන් අර්ථ දක්වයි.

template <class T>
DynArray<T>::DynArray(int size, int capacity){
    if (capacity >= size){
        this->size_ = size;
        this->capacity_ = capacity;
        data = new T[capacity];
    }
    //    for (int i = 0; i < size; ++i) {
    //        data[i] = 0;
    //    }
}

template <class T>
DynArray<T>::DynArray(const DynArray& d1){
    //clear();
    //delete [] data;
    std::cout << "copy" << std::endl;
    this->size_ = d1.size_;
    this->capacity_ = d1.capacity_;
    data = new T[capacity()];
    for(int i = 0; i < size(); ++i){
        data[i] = d1.data[i];
    }
}

template <class T>
DynArray<T>::~DynArray(){
    delete [] data;
}

template <class T>
T& DynArray<T>::operator[]( const int index){
    return at(index);
}

template <class T>
void DynArray<T>::operator=(const DynArray<T>& d1){
    if (this->size() > 0) {
        clear();
    }
    std::cout << "assign" << std::endl;
    this->size_ = d1.size_;
    this->capacity_ = d1.capacity_;
    data = new T[capacity()];
    for(int i = 0; i < size(); ++i){
        data[i] = d1.data[i];
    }

    //delete [] d1.data;
}

template <class T>
int DynArray<T>::size(){
    return size_;
}

template <class T>
int DynArray<T>::capacity(){
    return capacity_;
}

template <class T>
void DynArray<T>::clear(){
    for( int i = 0; i < size(); ++i){
        data[i] = 0;
    }
    size_ = 0;
    capacity_ = 2;
}

template <class T>
void DynArray<T>::push_back(int n){
    if (size() >= capacity()) {
        std::cout << "grow" << std::endl;
        //redo the array
        T* copy = new T[capacity_ + 40];
        for (int i = 0; i < size(); ++i) {
            copy[i] = data[i];
        }

        delete [] data;
        data = new T[ capacity_ * 2];
        for (int i = 0; i < capacity() * 2; ++i) {
            data[i] = copy[i];
        }
        delete [] copy;
        capacity_ *= 2;
    }
    data[size()] = n;
    ++size_;
}

template <class T>
void DynArray<T>::pop_back(){
    data[size()-1] = 0;
    --size_;
}

template <class T>
T& DynArray<T>::at(const int n){
    if (n >= size()) {
        throw std::runtime_error("invalid index");
    }
    return data[n];
}

template <class T>
T& DynArray<T>::back(){
    if (size() == 0) {
        throw std::runtime_error("vector is empty");
    }
    return data[size()-1];
}

template <class T>
T& DynArray<T>::front(){
    if (size() == 0) {
        throw std::runtime_error("vector is empty");
    }
    return data[0];
    }

2
බොහෝ අය ශීර්ෂ ගොනුවක් ප්‍රභව ගොනු වලට අර්ථ දැක්වීම් ප්‍රචාරණය කරන ඕනෑම දෙයක් ලෙස අර්ථ දක්වනු ඇත. එබැවින් ඔබ ".template" ගොනු දිගුව භාවිතා කිරීමට තීරණය කර ඇති නමුත් ඔබ ශීර්ෂ ගොනුවක් ලියා ඇත.
ටොමී
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.