Search code examples
c++polymorphismvirtualconstexprc++20

Is it possible to enforce, at compile time, that two derived classes would always return different values for an overriding function?


Is it possible to enforce, at compile time, that the following is acceptable:

class B {
public:
    virtual constexpr const char* getKeyStr() const = 0;
};

class D1 : public B {
public:
    constexpr const char* getKeyStr() const override { return "D1"; }
};

class D2 : public B {
public:
    constexpr const char* getKeyStr() const override { return "D2"; }
};

... But the following is not? We don't want D1 and D2 to return the same key string:

class B {
public:
    virtual constexpr const char* getKeyStr() const = 0;
};

class D1 : public B {
public:
    constexpr const char* getKeyStr() const override { return "D1"; }
};

class D2 : public B {
public:
    constexpr const char* getKeyStr() const override { return "D1"; } // can we error out here at compile time?
};

Clarifications:

  1. I am only showing two derived classes in this example, but what I am trying to achieve is to post this constraint on any number of derived classes.

  2. The underlying problem to solve: I am thinking about a serializing/deserializing application, where each object with the same base class will be able to generate a textual/string representation of itself to be written to a file and, when given that string back (let's call it the content-string), will be able to reconstruct the corresponding data.

    During deserialization, the application code should be able to tell from a key part of the content-string, let's call it the key-string, what derived object should be reconstructed. Therefore, the key-string needs to be unique for each derived class. I know type_info::name could be unique, but it is not customizable (or compiler independent?).

  3. Regarding the getKeyStr() function (corresponding to the key-string mentioned above), it should always return the same string for all objects of the same derived class.


Solution

  • If you can have a list of all Derived classes, you might do something like:

    template <typename... Ts>
    bool have_unique_keys()
    {
        std::string_view keys[] = {Ts{}.getKeyStr()...}; // requires constexpr default constructor
                                                         // static method might be more appropriate
        std::sort(std::begin(keys), std::end(keys)); // constexpr in C++20
        auto it = std::adjacent_find(std::begin(keys), std::end(keys));
        return it != std::end(keys);
    }
    
    static_assert(have_unique_keys<>(D1, D2, D3));