Skip to content

Mzying2001/cppsharp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CppSharp

A header-only C++ library that brings C#-style Delegate, Event, and Property patterns to C++.

No dependencies, no build step — just drop the headers into your project and #include them.

Features

Delegate (delegate.h)

A multicast delegate that supports storing and invoking multiple callable objects, closely modeled after C# Delegate.

  • Multicast — attach multiple handlers via +=, invoke them all with ()
  • Type aliasesAction<Args...>, Func<T1, ..., TResult>, Predicate<T> mirror their C# counterparts
  • Any callable — free functions, member functions (const and non-const), lambdas, and functors
  • Equality — delegates can be compared (==/!=) and checked against nullptr
  • Exception-safe — copy assignment provides strong exception safety guarantee

Event (event.h)

An event accessor that exposes a private delegate through a public event, enabling C#-style encapsulated event semantics.

  • Member events — expose a private delegate via field pointer or getter method on the owner object
  • Static events — bind to a global/static delegate via a free function accessor
  • += / -= — add or remove event handlers, just like C#
  • EventArgs — a base event arguments struct (extend as needed)
  • EventHandler<TSender, TEventArgs> — a convenience type alias for Delegate<void(TSender &, TEventArgs &)>

Property (property.h)

A property abstraction with getter/setter semantics, closely modeled after C# properties.

  • Read-writeProperty<T> with both getter and setter
  • Read-onlyReadOnlyProperty<T> with getter only
  • Write-onlyWriteOnlyProperty<T> with setter only
  • Member and static — bind to instance methods or static/free functions
  • Field binding — directly bind to a data member as a shortcut
  • Rich operators — arithmetic, bitwise, comparison, increment/decrement, subscript, dereference, and compound assignment all work transparently through the property
  • operator-> — access the underlying value's fields without calling Get() first

Quick Start

Clone or copy the include/ directory into your project, then:

#include "delegate.h"
#include "event.h"
#include "property.h"

Requires C++11 or later.

Usage — Delegate

Basic event pattern

#include "delegate.h"
#include <iostream>

class Button
{
public:
    Action<Button *> Clicked;

    void Click()
    {
        if (Clicked) {
            Clicked(this);
        }
    }
};

void OnClick(Button *)
{
    std::cout << "Button clicked!" << std::endl;
}

int main()
{
    Button btn;
    btn.Clicked += OnClick;
    btn.Click(); // prints: Button clicked!
}

Multicast

Multiple handlers can be attached; all of them are invoked in order:

btn.Clicked += OnClick;
btn.Clicked += [](Button *) {
    std::cout << "Lambda handler" << std::endl;
};
btn.Click();
// Output:
//   Button clicked!
//   Lambda handler

Removing a handler

btn.Clicked -= OnClick; // removes the exact callable

Member function binding

class Logger
{
public:
    void Log(Button *)
    {
        std::cout << "Logger::Log" << std::endl;
    }
};

Logger logger;
btn.Clicked.Add(logger, &Logger::Log);

Func with return value

Func<int, int, int> add;
add += [](int a, int b) { return a + b; };
int result = add(3, 4); // result == 7

Usage — Event

Basic member event

#include "event.h"
#include <iostream>

class Button
{
    Delegate<void()> _clicked;

public:
    Event<Delegate<void()>> Clicked{
        Event<Delegate<void()>>::Init(this)
            .Delegate<&Button::_clicked>()};

    void Click()
    {
        if (_clicked) {
            _clicked();
        }
    }
};

int main()
{
    Button btn;
    btn.Clicked += []() { std::cout << "Clicked!" << std::endl; };
    btn.Click(); // prints: Clicked!
}

Member function accessor

If the delegate is accessed through a getter method instead of a field:

class Button
{
    Delegate<void()> _clicked;

    Delegate<void()> &GetClicked() { return _clicked; }

public:
    Event<Delegate<void()>> Clicked{
        Event<Delegate<void()>>::Init(this)
            .Delegate<&Button::GetClicked>()};

    void Click() { if (_clicked) _clicked(); }
};

Static event

Delegate<void()> &GetGlobalDelegate()
{
    static Delegate<void()> d;
    return d;
}

Event<Delegate<void()>> GlobalClicked{
    Event<Delegate<void()>>::Init()
        .Delegate(GetGlobalDelegate)};

EventHandler with sender and args

class Button
{
    EventHandler<Button> _clicked;

public:
    Event<EventHandler<Button>> Clicked{
        Event<EventHandler<Button>>::Init(this)
            .Delegate<&Button::_clicked>()};

    void Click()
    {
        if (_clicked) {
            EventArgs args;
            _clicked(*this, args);
        }
    }
};

int main()
{
    Button btn;
    btn.Clicked += [](Button &sender, EventArgs &args) {
        std::cout << "Handled!" << std::endl;
    };
    btn.Click(); // prints: Handled!
}

Usage — Property

Basic read-write property

#include "property.h"
#include <iostream>
#include <string>

class Person
{
    int _age = 0;

public:
    Property<int> Age{
        Property<int>::Init(this)
            .Getter([](Person *self) { return self->_age; })
            .Setter([](Person *self, int value) {
                if (value >= 0) self->_age = value;
            })};
};

int main()
{
    Person p;
    p.Age = 25;
    std::cout << p.Age << std::endl; // 25
}

Using member functions

class Person
{
    int _age = 0;

    int getAge() const { return _age; }
    void setAge(int value) { _age = value; }

public:
    Property<int> Age{
        Property<int>::Init(this)
            .Getter<&Person::getAge>()
            .Setter<&Person::setAge>()};
};

Direct field binding

If no custom logic is needed, bind directly to a data member:

Property<int> Age{
    Property<int>::Init(this)
        .Getter<&Person::_age>()
        .Setter<&Person::_age>()};

Read-only property

class Circle
{
    double _radius = 1.0;

public:
    ReadOnlyProperty<double> Area{
        Property<double>::Init(this)
            .Getter([](Circle *self) {
                return 3.14159265 * self->_radius * self->_radius;
            })};
};

Static property

class App
{
    static std::string &nameStorage()
    {
        static std::string name = "MyApp";
        return name;
    }

public:
    static Property<std::string> Name{
        Property<std::string>::Init()
            .Getter([]() { return nameStorage(); })
            .Setter([](const std::string &v) { nameStorage() = v; })};
};

Operator usage

Properties support arithmetic, comparison, and compound operators:

Person p;
p.Age = 10;
p.Age += 5;       // Age is now 15
p.Age++;          // Age is now 16
std::cout << p.Age * 2 << std::endl; // 32

Accessing fields via operator->

class Config
{
public:
    struct Data { int x; int y; };
    Data _data{1, 2};

    Property<Data> Values{
        Property<Data>::Init(this)
            .Getter<&Config::_data>()
            .Setter<&Config::_data>()};
};

Config cfg;
std::cout << cfg.Values->x << std::endl; // 1

Project Structure

include/
    delegate.h    — Delegate, Action, Func, Predicate
    event.h       — Event, EventArgs, EventHandler
    property.h    — Property, ReadOnlyProperty, WriteOnlyProperty

License

MIT

About

A header-only C++ library that brings C#-style Delegate, Event, and Property patterns to C++.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages