C++模板类中模板函数的特化

发布于 2024-10-17 08:21:35 字数 1251 浏览 2 评论 0原文

用于专门化模板类内的模板函数的 C++ 语法是什么?例如,考虑我有以下两个类及其用法。我希望能够为不同类型提供方法 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;
}

我已经尝试猜测专业化的正确语法至少一个小时了,但无法弄清楚任何可以编译的内容。任何帮助将不胜感激!

What is the C++ syntax for specializing a template function that's inside a template class? For example, consider that I have the following two classes and their usage. I would like to be able to provide specialized implementations of the method X::getAThing() for different types. E.g.: int, std::string, arbitrary pointer or class, etc.

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

I've been trying to guess at the correct syntax for the specialization for at least an hour, and can't figure anything out that will compile. Any help would be greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

如果没结果 2024-10-24 08:21:35

AFAIK(标准专家可以纠正我),如果不专门化类本身,您就无法专门化类模板的模板化函数......

即我认为以下内容可行:

template <> template <> int X<Y>::getAThing<int>(std::string param) {
   return getIntThing(param); // Some function that crunches on param and returns an int.
}

AFAIK (and the standards experts can correct me), you cannot specialize a templated function of a class template without specializing the class itself...

i.e. the following I think will work:

template <> template <> int X<Y>::getAThing<int>(std::string param) {
   return getIntThing(param); // Some function that crunches on param and returns an int.
}
分分钟 2024-10-24 08:21:35

C++ 没有函数模板的部分特化的概念。但是,您可以通过函数重载获得与完全专业化相同的效果。

我假设你有这样的东西,这确实是唯一的方法之一。

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”函数,并且可能根本不会使用内部模板。

C++ has no concept of partial specialization for function templates. However, you can get the same effect as full specialization through function overloading.

I am assuming you have something like this, which is really one of the only ways to do it.

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

In this case, you specialize "myFunction()" by declaring ordinary member functions with the desired type. C++'s function overloading rules should give you what you want, e.g.

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

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

The compiler will use the "std::string" function where appropriate, and may never use the inner template at all.

稚然 2024-10-24 08:21:35

所以,我采取不同的方法来回答你的问题。我将从某种能满足您的要求并且有效的东西开始。然后也许我们可以弄清楚如何将其排列成更接近您真正想要的东西:

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

这是另一个可行的想法,虽然不完全是您想要的,但更接近。我想你自己已经想到了。它使用类型推导的方式也相当丑陋。

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

我建议在半私有实用程序命名空间中声明 getThingFunctorFriendlyGetThing

So, I'm taking a different approach to answering your question. I'm going to start from something that sort of does what you want, and works. And then maybe we can figure out how to permute it into something closer to what you really want:

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

Here is another idea that sort of works, and isn't exactly what you want, but is closer. I think you've thought of it yourself. It's also rather ugly in the way it uses type deduction.

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

I would recommend declaring getThingFunctor and friendlyGetThing in a semi-private utility namespace.

岁吢 2024-10-24 08:21:35

对于好奇的人来说,这可能是我将在自己的代码中采用的解决方案。这与 Omnifarious 的答案略有不同,无需额外的课程。我仍然支持 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;
}

For the curious, this is probably the solution I'm going to go with in my own code. This is a slight variation on Omnifarious's answer, that eliminates the need for an extra class. I still give props to Omnifarious, as he did most of the leg work:

#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;
}
五里雾 2024-10-24 08:21:35

尝试

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

这个仍然无法编译,但它比你的更接近。

我认为你不能让全体成员专业化。您必须先指定类模板的特定特化,然后才能开始特化其成员。

Try

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

This still doesn't compile, but it's closer than you had.

I think you can't specialize members en masse. You have to specify a particular specialization of the class template before you can start specializing its members.

一页 2024-10-24 08:21:35

这是迄今为止我见过的最简单、最容易的方法:

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
}

Here's the simplest, easiest way I've seen so far to do this:

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文