模板类中模板函数的 C++ 特化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4994775/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ specialization of template function inside template class
提问by Ogre Psalm33
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.
专门化模板类中的模板函数的 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;
}
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!
我一直试图猜测专业化的正确语法至少一个小时,但无法弄清楚可以编译的任何内容。任何帮助将不胜感激!
采纳答案by Omnifarious
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.
我建议在半私有实用程序命名空间中声明getThingFunctor
和friendlyGetThing
。
回答by Nim
AFAIK (and the standards experts can correct me), you cannot specialize a templated function of a class template without specializing the class itself...
AFAIK(标准专家可以纠正我),如果不专门化类本身,就不能专门化类模板的模板化函数......
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.
}
回答by Zack Yezek
C++ has no concept of partial specialization for function templates. However, you can get the same effect as full specialization through function overloading.
C++ 没有函数模板的偏特化概念。但是,您可以通过函数重载获得与完全特化相同的效果。
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.
在这种情况下,您可以通过声明具有所需类型的普通成员函数来专门化“myFunction()”。C++ 的函数重载规则应该给你你想要的,例如
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.
编译器将在适当的情况下使用“std::string”函数,并且可能根本不会使用内部模板。
回答by Ogre Psalm33
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:
出于好奇,这可能是我将在自己的代码中采用的解决方案。这是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;
}
回答by user524177
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
}
回答by Ben Voigt
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 particularspecialization of the class template before you can start specializing its members.
我认为你不能把成员集中起来。在开始专门化其成员之前,您必须指定类模板的特定专门化。