0

I have a non-templated class called Allocator which implements

template<class T>
Buffer<T> allocate(size_t n) { ... }

This function invokes a virtual unimplemented non-templated function in the same class

virtual Buffer<std::byte_t> allocate(size_t size, size_t align) = 0;

This non-templated allocate() function is overriden by derived classes. The idea is that the non-templated allocate function allocates std::bytes with given alignment and as such can be used by the templated function. The templated function is a essentially a pretified call to the byte-allocation function. It automatically picks up the alignment of the type T and calls

allocate(n * sizeof(T), alignof(T));

which works fine when derived classes are used.

Derived classes would need to implement the byte-allocation function and automatically have the typed-object-allocation function through inheritance:

So, I have a class Page : public Allocator that does exactly that but it seems that it cannot call the allocate<T>(...) function. If I do

Page page{...};

... = page.allocate<int>(10);

then I get the following error from VSCode intellisense:

A pointer to a bound function may only be used to call the function

and

expected primary-expression before '>' token

from g++ 12.1.0 Rev3 (the token that g++ specifically shows is the > after <int). It seems that g++ won't even pretend to see the allocate<T>(...) as existing.

On the other hand, doing this works fine:

((Allocator *) &page)->allocate<int>(10);

Is there some specific reason why the derived class cannot invoke the templated function in the base class directly? Why do I have to cast it to a pointer of the base class?

Paul Deva
  • 11
  • 2
  • Somewhere in the body of `Page`, add this line: `using Allocator::allocate;`. [See also](https://en.cppreference.com/w/cpp/language/using_declaration#In_class_definition) – Igor Tandetnik Sep 05 '22 at 14:01
  • @IgorTandetnik that does allow me to invoke `page.allocate(10)`, thanks. Still not sure why this wouldn't be possible by default, and it seems that every derived class will need the `using` statement. – Paul Deva Sep 05 '22 at 14:10
  • 2
    A name declared in derived class hides the same name from base class. Name lookup searches for names starting from the innermost scope and moving outwards, and stops as soon as it finds a declaration of that name - even if it later turns out that the entity it found is not viable. That's why, starting from `Page`, `Page::allocate` is found but not `Allocator::allocate`. The `using` declaration brings `Allocator::allocate` into the scope of the derived class, allowing it to be found. If you don't want to go through these gymnastics, simply give the two functions different names. – Igor Tandetnik Sep 05 '22 at 14:13
  • I'll use your solution. I expected the type specifier to provide the extra context needed to find the templated function. Thank you for the direct explanation – Paul Deva Sep 05 '22 at 14:16
  • Why not make the templated `allocate` a free function, taking a (const) reference to an Allocator instance? Then you wouldn't need the using statement and the intent would be clear. – joergbrech Sep 05 '22 at 15:57

0 Answers0