1

I'm relatively new to C++ templating and trying to figure out partial template specialization. I'm implementing several related data structures using templates: a Bloom filter (based on bit arrays) for probabilistic presence/absence queries, and a counting Bloom filter (with integers arrays) for abundance queries. I'm starting from the following class definition.

template<typename ElementType, typename CounterType, size_t maxcount>
class filter
{
    public:
        explicit filter(std::vector<size_t> array_sizes);
        void add(ElementType element);
        CounterType get(ElementType element);

    protected:
        std::vector<std::vector<CounterType>> _arrays;
};

The generic implementation of both add and get is correct, but get could be optimized for the bit array based Bloom filter. If I just try to add a method with the signature...

template<typename ElementType>
bool filter<ElementType, bool, 1>::get(ElementType element);

...I get the following error message from the compiler.

error: nested name specifier 'filter<ElementType, bool, 1>::'
    for declaration does not refer into a class, class template
    or class template partial specialization

With a bit of reading, I learned that individual methods cannot be partially specialized unless the entire class is partially specialized. That's actually convenient anyway, as that gives me a chance to provide new labels for the (partially) specialized classes. I added this to the bottom of my header...

template<typename ElementType> class bloomfilter : public filter<ElementType, bool, 1> {};
template<typename ElementType> class countfilter : public filter<ElementType, uint8_t, 255> {};
template<typename ElementType> class bigcountfilter : public filter<ElementType, uint32_t, 8589934591> {};

...and changed the method signature from...

template<typename ElementType>
bool filter<ElementType, bool, 1>::get(ElementType element);

...to...

template<typename ElementType>
bool bloomfilter<ElementType>::get(ElementType element);

Apparently this isn't enough. I need to explicitly define the bloomfilter::get method in the partially specialized class definition.

template<typename ElementType>
class bloomfilter : public filter<ElementType, bool, 1>
{
    public:
        bool get(ElementType element);
};

But now the compiler is complaining that _arrays is an undeclared identifier. It's not until I add this that it compiles correctly.

template<typename ElementType>
class bloomfilter : public filter<ElementType, bool, 1>
{
    public:
        bool get(ElementType element);

    protected:
        std::vector<std::vector<bool>> _arrays;
};

Why do I have to explicitly define get and _arrays in the partially specialized template class? Why aren't they inherited from the generic class?

Daniel Standage
  • 8,136
  • 19
  • 69
  • 116

2 Answers2

3

Pretty sure your problem is that you need to need to qualify the name _arrays with this. Try changing all instances of _arrays to this->_arrays.

In C++, in order to access a template base class's member you must further qualify the name in order to clarify whether or not the name is dependent on the template argument to the base class (I think). If you're interested in more technical details of this feature (explained better than I could), look here.

Community
  • 1
  • 1
0

Comment

You may consider tag dispatching:

#include <iostream>
#include <vector>
using size_t = std::size_t;

template<typename ElementType, typename CounterType, size_t maxcount>
class filter
{
    private:
    template <typename C, size_t>
    struct Tag {};

    using bloom_filter_tag = Tag<bool, 1>;

    template <typename Tag>
    CounterType get_dispatch(Tag, ElementType element) {
        std::cout << "generic\n";
        return CounterType{};
    }

    CounterType get_dispatch(bloom_filter_tag, ElementType element) {
        std::cout << "bloom filter\n";
        return CounterType{};
    }


    public:
    CounterType get(ElementType element) {
        return get_dispatch(Tag<CounterType, maxcount>(), element);
    }
};


int main() {
    filter<int, bool, 1> bloom;
    bloom.get(1);
    filter<int, double, 2> generic;
    generic.get(1);
}

However, define cindy const is actually answering your question.

Community
  • 1
  • 1