Re: Specialization of member functions without inheritance
"Allan Douglas" <allandouglas@gmail.com> wrote in
news:1171497259.272126.205790@j27g2000cwj.googlegroups.com:
Hello,
I'm trying to make a method (myfunc) that returns a value if a
template
parameter is non-void, or just don't return a value if the parameter
is void.
The test code is here:
int main() {
test2<int, int> t2int;
test2<void, int> t2void;
std::cout << t1int.myfunc(42) << std::endl;
t2int.otherfunc1();
t2void.myfunc(42);
t2void.otherfunc1();
return 0;
}
I found a solution using inheritance:
template <typename T1, typename T2>
class test2 : public test2base<T1, T2> {
public:
T1 myfunc(T2 x) {
[snip]
template <typename T>
class test2<void, T> : public test2base<void, T> {
public:
void myfunc(T x) {
[snip]
There is a way to specialize only the member function? The FAQ doesn't
talk so much about class and function members specialization.
What is your real goal to users of test2 in having a void function?
You can't piecewise specialize a class, but you can get the same
effect by delegating to a base class, and specializing (or not) as
needed. The following compiles on VC++ 2003 and gcc 3.4.6.
#include <iostream>
#include <boost/function.hpp>
using namespace std;
template <typename T, typename U>
struct FnDelegate
{
explicit FnDelegate(boost::function<T(U)> i_fn):m_fn(i_fn) {}
T doit(U u)
{
return m_fn(u);
}
private:
boost::function<T(U)> m_fn;
};
#ifdef PARTIALLY_SPECIALIZED
template <typename U>
struct FnDelegate<void, U>
{
explicit FnDelegate(boost::function<void(U)>){}
void doit(U u)
{
cout << "partially specialized" << endl;
}
};
#endif
template <typename T, typename U>
struct Doer: private FnDelegate<T, U>
{
explicit Doer(boost::function<T(U)> i_fn):FnDelegate<T,U>(i_fn){}
using FnDelegate<T,U>::doit;
};
void retVoid(int x)
{
cout << "retVoid got " << x << endl;
}
int retInt(int x)
{
cout << "retInt got " << x << endl;
return x;
}
int main(int argc, char const * argv[])
{
Doer<void, int> doer1(retVoid);
Doer<int, int> doer2(retInt);
doer1.doit(1);
int y = doer2.doit(2);
return 0;
}
You can partially specialize FnDelegate to do something different
altogether. If you need to have Doer have different constructor
behavior, you can probably overload the constructors with an SFINAE
utility, such as boost::enable_if, checking for type equality of
return type for void. For now it's an exercise for the reader to make
that work!
A related technique to all of this is to use return value proxies.
The template version provides an operator T() to get the value. The
void version converts it into something else of use that can easily be
swallowed.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]