Search code examples
c++static-assertcompile-time-type-checking

How to static_assert to check function signature is correct


The Code

I have a templated type that follows the Observer Pattern.

template <typename T>
class Subject {
public:
    template <template<typename> typename Observer>
    void AddObserver(Observer<T>& observer)
    {
        observers.push_back([&](const T& value) { observer.OnEvent(value); });
    }

    void Event(const T& value) const
    {
        for (auto& o : observers) { 
            o.OnEvent(value) 
        }
    }

private:
    std::vector<std::function<void(const T&)>> observers;
};

The above works great but only so long as the Observer is a templated type. So I can modify the template signature and accept any type, regardless of whether they are templated.

    template <typename Observer>
    void AddObserver(Observer& observer)
    {
        observers.push_back([&](const T& value) { observer.OnEvent(value); });
    }

The Issue

But now there aren't any compile time checks on type matching between the Subject and the Observer. (EDIT it has been pointed out that there is no guarantee that Observer<T> actually uses T in its OnEvent function signature)

I'd like to add a static cast to the function that checks that the two types Subject<**T**> and the Observer::OnEvent(const **T**&) are the same, to prevent automagic type conversions. Something like the below.

static_cast(std::is_same<T, **type_of_first_param**(Observer::OnEvent)>::value, "Subject/Observer type mistatch.");

Possible approach that I need help with

If I cannot extract the type from the function signature, perhaps I can construct a function signature to which I can compare it?

static_cast(std::is_same<**Observer::MadeUpFunc(const T&)**, Observer::OnEvent>::value, "Subject/Observer type mistatch.");

I'm investigating this QA, and I'm pretty sure it holds the answer I need, just need some time and perhaps guidance to figure it out.

I have tried the following, but get the compile time error

typename specifier refers to non-type member 'OnEvent' in 'Observer'

static_assert(std::is_same<typename Observer::OnEvent, void (Observer::*)(const T&...)>::value, "");

What I have tried



Solution

  • It's not clear to me what restrictions you want here. The most restrictive would be to enforce something like:

    static_assert(std::is_same_v<decltype(&Observer::OnEvent),
                                 void (Observer::*)(const T&) const>);
    

    where the OnEvent function couldn't be a template, it couldn't return anything aside from void, it would be required to be marked const, and it would have to take const T&, even if T is int.