I had a wrong perception that template
function in a class
is instantiated only if it's invoked. See the below simple code:
template<typename T>
struct A
{
T *p;
T& operator * () { return *p; }
};
int main ()
{
A<int> ai; // ok
int i = *ai; // works fine
A<void> av; // compiler complains even "*av" is not called
}
Just while declaring A<void>
, compiler errors out as:
error: forming reference to void
I tried to specialize the function for void
outside the template as below:
template<>
void A<void>::operator * () {}
But it doesn't help and gives error as:
error: no member function ‘operator*’ declared in ‘A<void>’
Is there any way to fix this with C++03 ?
What about
template < typename T >
struct ReferenceOrVoid
{ typedef T& Value; };
template < >
struct ReferenceOrVoid < void >
{ typedef void Value; };
template<typename T>
struct A
{
T *p;
typename ReferenceOrVoid < T > :: Value
operator * () { return *p; }
};
Of course it depends what you want A
to behave in case T
is void
. You can also specialise the whole A
struct for void
, of course.
The signature of the function will be instantiated, the body of the function will not. T
is substituted in the whole class definition, no matter if you're using the function or not. Note that this:
template<typename T>
struct A
{
T *p;
T *operator * () { return p->aklsdjlkasjd(); }
};
int main ()
{
A<void> av;
}
Will compile since you're not using operator*
.
I think it is sufficient if you give the function a different return type for void
:
template <typename T>
struct is _void {
enum { value = false };
};
template <>
struct is_void<> {
enum { value = true };
};
struct A {
...
typename enable_if<!is_void<T::value>, T&>::type
operator*() {
...
}
};
Since the signature may still be checked you may need to use a conditional type, e.g., making it void
when instantiated with void
:
template <bool, typename T1, typename>
struct conditional {
typedef T1 type;
};
template <typename T1, typename T2>
struct conditional<false, T1, T2> {
typedef T2 type;
};