1

When I try to call a templated function the compiler does not recognise the angle brackets for what they are.

I have one class called ArrayOfStacks which works perfectly fine when tested. I have another called GenericChunkAllocator which has a static member of type ArrayOfStacks. When I call the ArrayOfStacks member in GenericChunkAllocator the templating doesn't work correctly as described above.

For the purposes of testing I created the simplest function I could void foo() just to show the errors, the same errors occur in "real" use.

Any help would be greatly appreciated.

Relevant code and compiler errors are below.

chunkAllocator.hpp:

#pragma once

#include <array>
#include <vector>
#include <utility>
#include <memory>

#include "log2.hpp"
#include "accessParameterPack.hpp"
#include "cumulativeSumParameterPack.hpp"
#include "standardAllocatorInterface.hpp"


namespace awmms
{
    
    namespace memoryManagement
    {
        template<size_t... stackSizes>
        class ArrayOfStacks
        {
            public:
                template<size_t stackNum>
                constexpr void push(void* element);
                template<size_t stackNum>
                constexpr void* pop();
                template<size_t stackNum>
                constexpr void* top();

                template<size_t stackNum>
                constexpr double currentCapacity();

            private:
                constexpr static std::array<size_t, sizeof...(stackSizes)> sm_stackSizes = {stackSizes...};
                constexpr static std::array<size_t, sizeof...(stackSizes)> sm_stackBottoms = cumulativeSumParameterPack<size_t, stackSizes...>((-1 * accessParameterPack<size_t, 0, stackSizes...>()));
                
                std::array<size_t, sizeof...(stackSizes)> m_stackIndexes = {};

                void* m_container[(... + stackSizes)];
        };

        struct RawMemoryAllocationRecord
        {
            void* ptr;
            size_t size;
        };

        template<int allocatorID, double defaultFillPercentage, size_t... stackSizes>
        class GenericChunkAllocator
        {
            public:
                template<size_t n>
                constexpr void* allocate();
                template<size_t n>
                constexpr void deallocate(void* p);

                template<size_t size>
                constexpr void fill(double percentage = defaultFillPercentage);
                constexpr void fillAll(double percentage = defaultFillPercentage);
            
                void foo();

            private:
                constexpr void emergencyFill();

                static awmms::memoryManagement::ArrayOfStacks<stackSizes...> sm_arrayOfStacks;

                static std::vector<RawMemoryAllocationRecord> sm_rawAllocations;
        };
    }

chunkAllocator.inl:

#pragma once

namespace awmms
{
    namespace memoryManagement
    {
        template<size_t... stackSizes>
        template<size_t stackNum>
        constexpr void ArrayOfStacks<stackSizes...>::push(void* element)
        {
            typedef ArrayOfStacks<stackSizes...> thisT; 

            if(m_stackIndexes[stackNum] < thisT::sm_stackSizes[stackNum])
            {
                this->m_container[thisT::sm_stackBottoms[stackNum] + this->m_stackIndexes[stackNum]] = element;
                this->m_stackIndexes[stackNum]++;
            }
        }
        template<size_t... stackSizes>
        template<size_t stackNum>
        constexpr void* ArrayOfStacks<stackSizes...>::pop()
        {
            typedef ArrayOfStacks<stackSizes...> thisT; 
            
            if(AWMMS_EXPECT(this->m_stackIndexes[stackNum] == 0, false))
            {
                return nullptr;
            }
            else
            {
                auto returnValue = this->m_container[thisT::sm_stackBottoms[stackNum] + this->m_stackIndexes[stackNum] - 1];
                this->m_stackIndexes[stackNum]--;
                return returnValue;
            }
        }
        template<size_t... stackSizes>
        template<size_t stackNum>
        constexpr void* ArrayOfStacks<stackSizes...>::top()
        {
            typedef ArrayOfStacks<stackSizes...> thisT; 
            
            return this->m_container[thisT::sm_stackBottoms[stackNum] + this->m_stackIndexes[stackNum] - 1];
        }

        template<size_t... stackSizes>
        template<size_t stackNum>
        constexpr double ArrayOfStacks<stackSizes...>::currentCapacity()
        {
            typedef ArrayOfStacks<stackSizes...> thisT; 
            
            size_t spaceLeft = thisT::sm_stackSizes[stackNum] - this->m_stackIndexes[stackNum];
            size_t spaceTotal = thisT::sm_stackSizes[stackNum];
            return static_cast<double>(spaceLeft) / static_cast<double>(spaceTotal);
        }




        template<int allocatorID, double defaultFillPercentage, size_t... stackSizes>
        //awmms::memoryManagement::ArrayOfStacks<stackSizes...> sm_arrayOfStacks = awmms::memoryManagement::ArrayOfStacks<stackSizes...>();
        awmms::memoryManagement::ArrayOfStacks<stackSizes...> sm_arrayOfStacks = {};
        template<int allocatorID, double defaultFillPercentage, size_t... stackSizes>
        std::vector<RawMemoryAllocationRecord> sm_rawAllocations = {};

        template<int allocatorID, double defaultFillPercentage, size_t... stackSizes>
        template<size_t n>
        constexpr void* GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes...>::allocate()
        {
            //typedef GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes...> thisT;
            //constexpr size_t ptrSize = n<4 ? static_cast<size_t>(awmms::log2(n)) - 1 : 0;
            //void* ptr = thisT::sm_arrayOfStacks.pop<ptrSize>();
            return nullptr;
        }
        template<int allocatorID, double defaultFillPercentage, size_t... stackSizes>
        template<size_t n>
        constexpr void GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes...>::deallocate(void* p)
        {
            return;
        }

        template<int allocatorID, double defaultFillPercentage, size_t... stackSizes>
        template<size_t size>
        constexpr void GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes...>::fill(double percentage)
        {
            return;
        }
        template<int allocatorID, double defaultFillPercentage, size_t... stackSizes>
        constexpr void GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes...>::fillAll(double percentage)
        {
            return;
        }
        
        template<int allocatorID, double defaultFillPercentage, size_t... stackSizes>
        constexpr void GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes...>::emergencyFill()
        {
            return;
        }

        template<int allocatorID, double defaultFillPercentage, size_t... stackSizes>
        void GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes...>::foo()
        {
            typedef GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes...> thisT;
            thisT::sm_arrayOfStacks.push<0>(nullptr);
            thisT::sm_arrayOfStacks.pop<0>();
        }
    }
}

I have created an instance of the class and called foo() from main. The errors are as follows:

/home/ebony/git/Ebony-Ayers/awmms/tests/src/../../src/chunkAllocator.inl: In member function ‘void awmms::memoryManagement::GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes>::foo()’:
/home/ebony/git/Ebony-Ayers/awmms/tests/src/../../src/chunkAllocator.inl:104:56: error: expected primary-expression before ‘)’ token
  104 |                         thisT::sm_arrayOfStacks.pop<0>();
      |                                                        ^
/home/ebony/git/Ebony-Ayers/awmms/tests/src/../../src/chunkAllocator.inl: In instantiation of ‘void awmms::memoryManagement::GenericChunkAllocator<allocatorID, defaultFillPercentage, stackSizes>::foo() [with int allocatorID = 0; double defaultFillPercentage = 5.0e-1; long unsigned int ...stackSizes = {10, 10, 10, 10, 10, 10}]’:
/home/ebony/git/Ebony-Ayers/awmms/tests/src/main.cpp:15:7:   required from here
/home/ebony/git/Ebony-Ayers/awmms/tests/src/../../src/chunkAllocator.inl:103:53: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
  103 |                         thisT::sm_arrayOfStacks.push<0>(nullptr);
      |                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
/home/ebony/git/Ebony-Ayers/awmms/tests/src/../../src/chunkAllocator.inl:104:52: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
  104 |                         thisT::sm_arrayOfStacks.pop<0>();
      | 
Ebony Ayers
  • 350
  • 1
  • 3
  • 9

1 Answers1

0

I believe your issue here is that you need to use the 'template' keyword because thisT is a dependent type.

thisT::sm_arrayOfStack.template push<0>(nullptr);

Due to details of 2 phase compilation of function templates, the compiler doesn't know whether push is a function template or a member variable during the first phase of compiling the template.

SirGuy
  • 10,660
  • 2
  • 36
  • 66