c++ специализация шаблонной функции внутри шаблонного класса

<p>каков синтаксис c++ для специализации шаблонной функции внутри класса шаблона? например, предположим, что у меня есть следующие два класса и их использование. я хотел бы иметь возможность предоставить специализированные реализации метода x :: getathing () для разных типов. например: int, std :: string, произвольный указатель или класс и т.д.</p><pre><code>template <class c1> class x { public: template<typename returnt> returnt getathing(std::string param); static std::string getname(); private: c1 thedata; }; // this works ok... template <class c1> std::string x<c1>::getname() { return c1::getname(); } // this blows up with the error: // error: prototype for 'int x<c1>::getathing(std::string)' does not match any in class 'x<c1>' template <class c1> template <typename returnt> int x<c1>::getathing(std::string param) { return getintthing(param); // some function that crunches on param and returns an int. } // more specialized definitions of getathing() for other types/classes go here... class y { public: static std::string getname() { return "y"; } }; int main(int argc, char* argv[]) { x<y> tester; int anintthing = tester.getathing<int>(std::string("param")); cout << "name: " << tester.getname() << endl; cout << "an int thing: " << anintthing << endl; } </code></pre><p>я пытался угадать правильный синтаксис для специализации, по крайней мере, час, и не могу понять, что скомпилировать. любая помощь будет принята с благодарностью!</p>

<p>поэтому я отвечаю на ваш вопрос по-другому. я собираюсь начать с того, что делает то, что вы хотите, и работает. и тогда, возможно, мы сможем выяснить, как превратить это в нечто более близкое к тому, что вы действительно хотите:</p><pre><code>#include <string> #include <iostream> int getintthing(const ::std::string ¶m); template <typename returnt> returnt getthingfree(const ::std::string ¶m); template <> int getthingfree<int>(const ::std::string ¶m) { return getintthing(param); } // more specialized definitions of getathing() for other types/classes // go here... template <class c1> class x { public: template<typename returnt> returnt getathing(std::string param); static std::string getname(); private: c1 thedata; }; // this works ok... template <class c1> std::string x<c1>::getname() { return c1::getname(); } // this also works, but it would be nice if i could explicitly specialize // this instead of having to explicitly specialize getthingfree. template <class c1> template <class rt> rt x<c1>::getathing(std::string param) { // some function that crunches on param and returns an rt. // gosh, wouldn't it be nice if i didn't have to redirect through // this free function? return getthingfree<rt>(param); } class y { public: static std::string getname() { return "y"; } }; int main(int argc, char* argv[]) { using ::std::cout; x<y> tester; int anintthing = tester.getathing<int>(std::string("param")); cout << "name: " << tester.getname() << '\n'; cout << "an int thing: " << anintthing << '\n'; } </code></pre><p>вот еще одна идея, которая вроде работает, и не совсем то, что вы хотите, но ближе. я думаю, что вы думали об этом сами. это также довольно уродливо в том смысле, что использует вывод типов.</p><pre><code>#include <string> #include <iostream> template <class c1> class x; int getintthing(const ::std::string ¶m) { return param.size(); } // you can partially specialize this, but only for the class, or the // class and return type. you cannot partially specialize this for // just the return type. otoh, specializations will be able to access // private or protected members of x<c1> as this class is declared a // friend. template <class c1> class friendlygetthing { public: template <typename return\_t> static return\_t getthing(x<c1> &xthis, const ::std::string ¶m, return\_t *); }; // this can be partially specialized on either class, return type, or // both, but it cannot be declared a friend, so will have no access to // private or protected members of x<c1>. template <class c1, typename return\_t> class getthingfunctor { public: typedef return\_t r\_t; return\_t operator()(x<c1> &xthis, const ::std::string ¶m) { return\_t *fred = 0; return friendlygetthing<c1>::getthing(xthis, param, fred); } }; template <class c1> class x { public: friend class friendlygetthing<c1>; template<typename returnt> returnt getathing(std::string param) { return getthingfunctor<c1, returnt>()(*this, param); } static std::string getname(); private: c1 thedata; }; // this works ok... template <class c1> std::string x<c1>::getname() { return c1::getname(); } class y { public: static std::string getname() { return "y"; } }; template <class c1> class getthingfunctor<c1, int> { public: int operator()(x<c1> &xthis, const ::std::string ¶m) { return getintthing(param); } }; // more specialized definitions of getathingfunctor for other types/classes // go here... int main(int argc, char* argv[]) { using ::std::cout; x<y> tester; int anintthing = tester.getathing<int>(std::string("param")); cout << "name: " << tester.getname() << '\n'; cout << "an int thing: " << anintthing << '\n'; } </code></pre><p>я бы порекомендовал объявить <code>getthingfunctor</code> и <code>friendlygetthing</code> в полуприватном пространстве имен утилит.</p>

<p>afaik (и эксперты по стандартам могут исправить меня), вы не можете специализировать шаблонную функцию шаблона класса, не специализируя сам класс ...</p><p>то есть следующее, я думаю, будет работать:</p><pre><code>template <> template <> int x<y>::getathing<int>(std::string param) { return getintthing(param); // some function that crunches on param and returns an int. } </code></pre>

<p>c++ не имеет понятия частичной специализации для шаблонов функций. однако вы можете получить тот же эффект, что и полная специализация, через перегрузку функций.</p><p>я предполагаю, что у вас есть что-то подобное, что на самом деле является единственным способом сделать это.</p><pre><code>template<class type> class myinterface { public: template<class return> return myfunction(return& ref, ....); }; </code></pre><p>в этом случае вы специализируете myfunction (), объявляя обычные функции-члены с желаемым типом. правила перегрузки функций c++ должны дать вам то, что вы хотите, например,.</p><pre><code>template<class type> class myinterface { public: template<class return> return myfunction(return& ref, ....); // string specialization std::string myfunction(std::string& ref, ...); }; </code></pre><p>компилятор будет использовать функцию «std :: string», где это уместно, и может вообще не использовать внутренний шаблон.</p>

<p>для любопытных, это, вероятно, решение, которое я собираюсь использовать в своем собственном коде. это небольшое изменение ответа <a href="https://stackoverflow.com/users/167958/omnifarious">omnifarious</a> , которое устраняет необходимость в дополнительном классе. я все еще даю реквизит <a href="https://stackoverflow.com/users/167958/omnifarious">всевышнему</a> , так как он делал большую часть работы ногами</p><pre><code>#include <iostream> #include <string> using namespace std; // important note: adaptingfunctor has no access to the guts of class x! // thus, this solution is somewhat limited. template<typename t1> class adaptingfunctor { public: t1 operator() (string param); }; // can specialize adaptingfunctor for each type required: template<> int adaptingfunctor<int>::operator() (string param) { return param.size(); // <=== insert required type-specific logic here } // additional specializations for each return type can go // here, without requiring specialization of class c1 for x... template <class c1> class x { public: template<typename returnt> returnt getathing(std::string param) { adaptingfunctor<returnt> adapter; return adapter(param); } static std::string getname(); private: c1 thedata; }; // template definition of class method works ok... template <class c1> std::string x<c1>::getname() { return c1::getname(); } class y { public: static std::string getname() { return "y"; } }; int main(int argc, char* argv[]) { x<y> tester; int anintthing = tester.getathing<int>(std::string("param")); cout << "name: " << tester.getname() << endl; cout << "an int thing: " << anintthing << endl; } </code></pre>

<p>пытаться</p><pre><code>template <> template <class t> int x<t>::template getathing<int>(std::string param) { return getintthing(param); } </code></pre><p>это все еще не компилируется, но это ближе, чем вы имели.</p><p>я думаю, что вы не можете специализировать членов в массовом порядке. вы должны указать<strong> конкретную </strong>специализацию шаблона класса, прежде чем сможете начать специализацию его членов.</p>