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.