37

テンプレートクラス内にあるテンプレート関数を特殊化するためのC++構文は何ですか?たとえば、次の2つのクラスとその使用法があるとします。さまざまなタイプのメソッドX::getAThing()の特殊な実装を提供できるようにしたいと思います。例:int、std :: string、任意のポインタまたはクラスなど。

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;
}

私は少なくとも1時間、特殊化の正しい構文を推測しようとしてきましたが、コンパイルされるものを見つけることができません。どんな助けでも大歓迎です!

4

6 に答える 6

22

AFAIK(および標準の専門家が私を修正できます)、クラス自体を専門化せずにクラステンプレートのテンプレート化された関数を専門化することはできません...

つまり、次のように機能すると思います。

template <> template <> int X<Y>::getAThing<int>(std::string param) {
   return getIntThing(param); // Some function that crunches on param and returns an int.
}
于 2011-02-14T17:20:01.297 に答える
9

C ++には、関数テンプレートの部分的な特殊化の概念はありません。ただし、関数のオーバーロードにより、完全な特殊化と同じ効果を得ることができます。

私はあなたがこのようなものを持っていると思います、それは本当にそれをする唯一の方法の1つです。

template<class TYPE>
class MyInterface {
public:
    template<class RETURN>
    RETURN myFunction(RETURN& ref, ....);
};

この場合、目的のタイプの通常のメンバー関数を宣言することにより、「myFunction()」を特殊化します。C ++の関数オーバーロードルールは、必要なものを提供する必要があります。

template<class TYPE>
class MyInterface {
public:
    template<class RETURN>
    RETURN myFunction(RETURN& ref, ....);

    // String specialization
    std::string myFunction(std::string& ref, ...);
};

コンパイラは、必要に応じて「std :: string」関数を使用し、内部テンプレートをまったく使用しない場合があります。

于 2012-04-13T14:31:29.473 に答える
7

だから、私はあなたの質問に答えるために別のアプローチを取っています。私は、あなたが望むことを実行し、機能するようなものから始めます。そして、おそらく私たちはそれをあなたが本当に欲しいものに近いものに並べ替える方法を理解することができます:

#include <string>
#include <iostream>

int getIntThing(const ::std::string &param);

template <typename returnT>
returnT getThingFree(const ::std::string &param);

template <>
int getThingFree<int>(const ::std::string &param)
{
   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';
}

これは、ある種の機能を備えた別のアイデアであり、正確にはあなたが望むものではありませんが、より近いものです。自分で考えたことがあると思います。また、型控除の使用方法もかなり醜いです。

#include <string>
#include <iostream>

template <class c1> class X;

int getIntThing(const ::std::string &param)
{
   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 &param,
                            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 &param) {
      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 &param) {
      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';
}

セミプライベートユーティリティの名前空間でgetThingFunctor宣言することをお勧めします。friendlyGetThing

于 2011-02-14T17:18:26.327 に答える
1

不思議なことに、これはおそらく私が自分のコードで使用するソリューションです。これはOmnifariousの回答のわずかなバリエーションであり、追加のクラスは必要ありません。彼が脚の仕事のほとんどをしたので、私はまだオムニファリアスに小道具を与えます:

#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;
}
于 2011-02-14T19:11:21.470 に答える
-2

試す

template <>
template <class T>
int X<T>::template getAThing<int>(std::string param)
{
   return getIntThing(param);
}

これはまだコンパイルされませんが、あなたが持っていたよりも近くにあります。

メンバーをまとめて専門化することはできないと思います。メンバーの特殊化を開始する前に、クラステンプレートの特定の特殊化を指定する必要があります。

于 2011-02-14T16:57:30.687 に答える
-2

これを行うためにこれまでに見た中で最も簡単で簡単な方法は次のとおりです。

template <class T1>
struct MyClass {
  template <class T2>
  void MyFunction();
};

template <class T1>
template <class T2>
void MyClass<T1>::MyFunction() {  // NOTE:  NO T2 on this line.
  // Code goes here
}
于 2011-05-04T16:36:19.043 に答える