2

I have a class "Ram" with a template parameter that specifies its bank size. e.g.

ram.hpp

#include <vector>
#include <array>
#include <cstdint>
#include <iostream>

template <uint16_t bank_sz>
class Ram
{
    public:
    uint8_t read(uint8_t bank, uint16_t adr) const;
    void write(uint8_t b, uint8_t bank, uint16_t adr);
    void resize(uint8_t nbanks);

    private:
    std::vector<std::array<uint8_t, bank_sz>> data_;
};

// explicit template instantiations
template class Ram<0x2000>;
template class Ram<0x1000>;

using Work_ram = Ram<0x1000>;
using Video_ram = Ram<0x2000>;

and the implementation:

ram.cpp

template <uint16_t bank_sz>
uint8_t Ram<bank_sz>::read(uint8_t bank, uint16_t adr) const
{
    if (bank > data_.size() || adr > bank_sz)
        throw std::out_of_range {"Invalid RAM address"};
    return data_[bank][adr];
}

template <uint16_t bank_sz>
void Ram<bank_sz>::write(uint8_t b, uint8_t bank, uint16_t adr)
{
    if (bank > data_.size() || adr > bank_sz)
        throw std::out_of_range {"Invalid RAM address"};
    data_[bank][adr] = b;
}

template <uint16_t bank_sz>
void Ram<bank_sz>::resize(uint8_t nbanks)
{
    data_.resize(nbanks);
}

When I try to use it, for example

#include "ram.hpp"
int main()
{
    Video_ram r {};
    r.resize(1);
    r.write(0xff, 0, 0);
    std::cout << r.read(0, 0);
    return 0;
}

I get the warning: "instantiation of function Ram<8192> required here, but no definition is available." Everything compiles and works as expected, though. Could this be because I seperated the declaration and implementation of the Ram class into different files? I thought it would be okay because of the explicit instantiation at the end of "ram.hpp".

dav
  • 626
  • 4
  • 21
  • 2
    Definitions of templates have to be completely in the header file. They cannot be put in the cpp file. – n314159 Nov 23 '19 at 21:50
  • @Kai What am I missing from this being a minimally reproducible example? – dav Nov 23 '19 at 21:53
  • Try placing the explicit instantiation at the bottom of the .cpp instead. – HolyBlackCat Nov 23 '19 at 21:54
  • Does the warning disappear if you add "extern" before your template instantiation in the header and move its non-extern variant at the end of ram.cpp? – Kit. Nov 23 '19 at 21:58
  • Please refer to [why can templates only be implemented in the header file](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – Vivick Nov 23 '19 at 21:58
  • @Kit yes this works. But according to the others the definitions have to be in the header file. Why is this working then? – dav Nov 23 '19 at 22:01
  • 2
    @DavidTran *"according to the others the definitions have to be in the header file"* They don't have to. Those 'others' don't know what an explicit instantiation is. – HolyBlackCat Nov 23 '19 at 22:02
  • @HolyBlackCat Thank you, that's what I though. Although this is allowed, would you say it's bad practice/code smell? I want template functionality but don't want the inconveniences of having declaration and implementation in the same file (having to recompile after any changes, etc.) – dav Nov 23 '19 at 22:05
  • I don't think it's a code smell. If it's what you need, use it. – HolyBlackCat Nov 23 '19 at 22:09
  • It's an optimization technique. It's "bad" if it's premature, as it breaks other optimization techniques, but sometimes people do need to optimize compile time and/or executable size. – Kit. Nov 23 '19 at 22:14

0 Answers0