Are all these overloads legal?

J

James

I am trying to create a wrapper template that can forward parameters from
the wrapper constructor to the wrapped object constructor. I have been
having some trouble, and the only way I can even think of getting it work is
to use a boatload of overloads. Here is some sample code:


#include <iostream>


struct fubar
{
fubar()
{
std::cout << "("
<< this
<< ")->fubar::fubar()"
<< std::endl;
}


~fubar()
{
std::cout << "("
<< this
<< ")->fubar::~fubar()"
<< std::endl;
}


void display()
{
std::cout << "("
<< this
<< ")->fubar::display()"
<< std::endl;
}
};


struct foo
{
fubar& m_fubar;


foo(fubar& fubar_, int x)
: m_fubar(fubar_)
{
std::cout << "("
<< this
<< ")->foo::foo()"
<< std::endl;
}


~foo()
{
std::cout << "("
<< this
<< ")->foo::~foo()"
<< std::endl;
}


void display_fubar()
{
m_fubar.display();
}
};


template<typename T>
struct wrapper : public T
{
template<typename P1>
wrapper(P1& p1)
: T(p1)
{

}


template<typename P1>
wrapper(P1 const& p1)
: T(p1)
{

}


template<typename P1, typename P2>
wrapper(P1& p1, P2& p2)
: T(p1, p2)
{

}


template<typename P1, typename P2>
wrapper(P1 const& p1, P2& p2)
: T(p1, p2)
{

}


template<typename P1, typename P2>
wrapper(P1& p1, P2 const& p2)
: T(p1, p2)
{

}


template<typename P1, typename P2>
wrapper(P1 const& p1, P2 const& p2)
: T(p1, p2)
{

}
};


int
main()
{
{
fubar fb;
wrapper<foo> f(fb, 5);
f.display_fubar();
}

return 0;
}




Notice all of the constructor overloads in the wrapper template... Are those
even legal? Can they get me into trouble? Will there be any ambiguity
problems?


One problem I can see... The number of overloads can get very high when the
number of parameters increases. I guess I can create a little program to
automatically generate all of them. Would that even be feasible?



Thanks!
 
M

Marcel Müller

James said:
Notice all of the constructor overloads in the wrapper template... Are
those even legal?

As far as I know you can overload whatever you want, as long as you do
not have exactly the same argument list twice. I.e. two overloaded
functions must not differ in the return type only.
Can they get me into trouble?

However, sometimes it might be quite difficult to avoid ambiguities when
calling the overloaded method.
> Will there be any
ambiguity problems?

Not in your example.

But change your code to

int
main()
{
{
volatile fubar fb;
wrapper<foo> f(fb, 5);
f.display_fubar();
}

return 0;
}

and this will change.

One problem I can see... The number of overloads can get very high when
the number of parameters increases.

Well variadic templates would be nice. If you have the option C++0x,
there is a straight forward solution for any number of arguments.

template<typename T>
struct wrapper : public T
{
template<typename... P1>
wrapper(P1... p1)
: T(p1...)
{

}
};

I guess I can create a little
program to automatically generate all of them. Would that even be feasible?


Feel free to do so, but I see no need for all of these methods. Do you
want to enforce reference parameters? If not

template<typename T>
struct wrapper : public T
{
template<typename P1>
wrapper(P1 p1)
: T(p1)
{

}

template<typename P1, typename P2>
wrapper(P1 p1, P2 p2)
: T(p1, p2)
{

}
};

will do the Job as well without any risk of ambiguity.


Marcel
 
J

James

Marcel Müller said:
James said:
Notice all of the constructor overloads in the wrapper template... Are
those even legal? [...]
Will there be any
ambiguity problems?

Not in your example.

But change your code to

int
main()
{
{
volatile fubar fb;
wrapper<foo> f(fb, 5);
f.display_fubar();
}

return 0;
}

and this will change.

Okay. Well, it does work when I add the proper overload and modify foo and
fubar accordingly:


template<typename P1, typename P2>
wrapper(P1 volatile& p1, P2 const& p2)
: T(p1, p2)
{

}



Well variadic templates would be nice. If you have the option C++0x, there
is a straight forward solution for any number of arguments.

template<typename T>
struct wrapper : public T
{
template<typename... P1>
wrapper(P1... p1)
: T(p1...)
{

}
};

Oh that would be great! However, I don't have that option.

DAMN!



Feel free to do so, but I see no need for all of these methods. Do you
want to enforce reference parameters? If not

template<typename T>
struct wrapper : public T
{
template<typename P1>
wrapper(P1 p1)
: T(p1)
{

}

template<typename P1, typename P2>
wrapper(P1 p1, P2 p2)
: T(p1, p2)
{

}
};

will do the Job as well without any risk of ambiguity.

Can I force reference parameters by doing something like:



#include <iostream>


struct fubar
{
fubar()
{
std::cout << "("
<< this
<< ")->fubar::fubar()"
<< std::endl;
}


~fubar()
{
std::cout << "("
<< this
<< ")->fubar::~fubar()"
<< std::endl;
}


void display()
{
std::cout << "("
<< this
<< ")->fubar::display()"
<< std::endl;
}
};


struct foo
{
fubar& m_fubar;


foo(fubar& fubar_, int x)
: m_fubar(fubar_)
{
std::cout << "("
<< this
<< ")->foo::foo()"
<< std::endl;
}


~foo()
{
std::cout << "("
<< this
<< ")->foo::~foo()"
<< std::endl;
}


void display_fubar()
{
m_fubar.display();
}
};


template<typename T>
struct wrapper : public T
{
template<typename P1, typename P2>
wrapper(P1 p1, P2 p2)
: T(p1, p2)
{

}
};


template<typename T>
class reference
{
T const& m_reference;


public:
reference(T const& ref)
: m_reference(ref)
{

}


operator T const& () const
{
return m_reference;
}


operator T& ()
{
return *const_cast<T*>(&m_reference);
}
};


template<typename T>
static reference<T>
create_ref(T const& ref)
{
return reference<T>(ref);
}


int
main()
{
{
fubar fb;
wrapper<foo> f(create_ref(fb), 5);
f.display_fubar();
}

return 0;
}




?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top