Compiler instantiates the function in a template c

2019-06-06 14:52发布

问题:

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 ?

回答1:

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.



回答2:

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*.



回答3:

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;
};