简体   繁体   中英

Template specialization for a class member function in order to not use increment operator on bool

In my application I use a class to flag elements that are inidicated by positive numbers (see code below). The template parameter of class Stamp is usually an unsigned integer . The advantage of flagging with a counter is, that clear() usually executes fast on huge vectors, as one increment of the counter invalidates all flags. Currently, only in my unit tests, I use boolean as template argument. Using boolean comes closest to the naive implementation of flagging numbers. But the increment operator for boolean is deprecated and will soon vanish from the standard and the compiler complains already about deprecation (not knowing that the part it's complaining about wouldn't even be executed in case of boolean ). How would you specialize method clear() for the boolean case? I could not get it right, I tried it by just adding the the following definition.

template<>
void Stamp<bool>::clear() {
    std::fill(stamped.begin(), stamped.end(), false);
}

Now the compiler complains about multiple definitions of clear() . How is template specialization done right in that case. And what other possibilities do I have to fix this class in modern c++?

template <class T> class Stamp {
private:
    std::vector<T> stamped;
    T stamp;

public:
    Stamp(unsigned int size) {
        stamped.resize(size, std::numeric_limits<T>::min());
        stamp = std::numeric_limits<T>::min();
    }

    ~Stamp() { }

    void clear() {
        if (stamp < std::numeric_limits<T>::max()) {
            stamp++;
        }
        else {
            std::fill(stamped.begin(), stamped.end(), std::numeric_limits<T>::min());
            stamp = std::numeric_limits<T>::min() + 1;
        }
    }

    void unset(unsigned int index) {
        assert(index < stamped.size());
        stamped[index] = std::numeric_limits<T>::min();
    }

    void set(unsigned int index) {
        assert(index < stamped.size());
        stamped[index] = stamp;
    }

    bool isStamped(unsigned int index) const {
        return stamped[index] == stamp;
    }
};

EDIT: Using the answer of @Constructor I could come up with a method specialization by adding another definition of clear() to the header like this:

template<>
inline void Stamp<bool>::clear() {
    std::fill(stamped.begin(), stamped.end(), false);
    stamp = true;
}

This is kind of ugly but it actually works. Neither compiler nor tests choke on it.

The full (or explicit) function template specialization is not a template. So you should treat it like a normal function.

There are two possibilities not to violate ODR (One Definition Rule) when you are working with functions or methods of classes:

1) place the declaration of the function/method in a header file and its definition in some cpp file:

// Stamp.h

template<>
void Stamp<bool>::clear();

// Stamp.cpp

template<>
void Stamp<bool>::clear()
{
    std::fill(stamped.begin(), stamped.end(), false);
    stamp = true;
}

2) mark it as inline and place its definition in your header file:

// Stamp.h

template<>
inline void Stamp<bool>::clear()
{
    std::fill(stamped.begin(), stamped.end(), false);
    stamp = true;
}

Unfortunately, you can't specialize member functions without specializing the whole class. It is a silly language limitation that exists for historical reasons that don't (in my opinion) apply any longer.

Instead of specializing the whole class, you can make Stamp<T> inherit from StampBase<T> which you then specialize.

template <typename T> class StampBase;

template <typename T> class Stamp : public StampBase<T> {
    // Code goes here!
    void clear() {
        StampBase<T>::clear_impl();
        // Rest of code.
    }
};

template <typename T> class StampBase {
protected:
    void clear_impl() { /* T is NOT a bool */ }
};

template <> class StampBase<bool> {
protected:
    void clear_impl() { /* T IS a bool */ }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM