My goal is to create a generic Event type that can be used in subscribe/notify architecture, but I am having trouble getting class member functions to work.
Event.hpp:
#ifndef EVENT_HPP
#define EVENT_HPP
#include <functional>
#include <unordered_set>
template <typename ... EventParameterTypes>
struct Event {
typedef void(*EventCallback)(EventParameterTypes ...);
template <typename ClassType>
Event &subscribe(ClassType *instance, void(ClassType::*eventCallback)(EventParameterTypes...)) {
auto bound = [=](EventParameterTypes&& ... params) { return ((instance)->*(eventCallback))(std::forward<EventParameterTypes>(params)...); };
return this->subscribe(bound);
}
Event &subscribe(EventCallback eventCallback) {
return this->addEventCallback(eventCallback);
}
void notify(EventParameterTypes ... types) {
for (const auto &it : this->m_eventCallbacks) {
if (it) (*it)(types...);
}
}
private:
std::unordered_set<EventCallback> m_eventCallbacks;
Event &addEventCallback(EventCallback eventCallback) {
auto foundIterator = std::find(this->m_eventCallbacks.begin(), this->m_eventCallbacks.end(), eventCallback);
if (foundIterator != this->m_eventCallbacks.end()) {
return *this;
}
this->m_eventCallbacks.insert(eventCallback);
return *this;
}
};
#endif //EVENT_HPP
Main.cpp:
#include "Event.hpp"
struct EventTest {
using MyEvent = Event<int>;
MyEvent myEvent;
};
void myEventCallback(int) {
//Stuff
}
struct EventListener {
void eventListenerCallback(int) {
//Stuff
}
};
int main() {
EventListener eventListener{};
EventTest eventTest{};
eventTest.myEvent.subscribe(&myEventCallback); //OK
eventTest.myEvent.subscribe(&eventListener, &EventListener::eventListenerCallback); //Compile error
}
Is there any way to resolve this? I have looked into std::bind but it only works with a certain amount of placeholders, and the lambda causes the function to be of a local lambda type.
You are hoping to somehow pack instance and eventCallback into a single function pointer. You can't do that, no more than you can pour an ocean into a thimble. One way out is to make EventCallback a typedef for a suitable specialication of std::function, as in
typedef std::function<void(EventParameterTypes ...)> EventCallback;
I won't be surprised if the rest of the code would just work after this, with no modifications.
Using #Igor Tandetnik s advice, I came up with the following (working) implementation:
Event.hpp
#ifndef EVENT_HPP
#define EVENT_HPP
#include <functional>
#include <functional>
#include <type_traits>
#include <vector>
template<typename T, typename... U>
size_t getFunctionAddress(std::function<T(U...)> f) {
typedef T(fnType)(U...);
fnType **fnPointer = f.template target<fnType *>();
if (fnPointer == nullptr) {
return 0;
}
return (size_t) *fnPointer;
}
template<typename ... EventParameterTypes>
struct Event {
template<class ClassType> using MemberPtr = void (ClassType::*)(EventParameterTypes...);
using EventCallback = std::function<void(EventParameterTypes ...)>;
template<class ClassType>
Event &subscribe(ClassType *instance, MemberPtr<ClassType> eventCallback) {
const auto bound = [=](EventParameterTypes &&... params) { return ((instance)->*eventCallback)(std::forward<EventParameterTypes>(params)...); };
return this->operator+=(bound);
}
Event &operator+=(EventCallback eventCallback) {
return this->addEventCallback(eventCallback);
}
template<class ClassType>
Event &unsubscribe(ClassType *instance, MemberPtr<ClassType> eventCallback) {
const auto bound = [=](EventParameterTypes &&... params) { return ((instance)->*eventCallback)(std::forward<EventParameterTypes>(params)...); };
return this->operator-=(bound);
}
Event &operator-=(EventCallback eventCallback) {
return this->removeEventCallback(eventCallback);
}
template<class ClassType>
bool isListenerRegistered(ClassType *instance, MemberPtr<ClassType> eventCallback) {
const auto bound = [=](EventParameterTypes &&... params) { return ((instance)->*eventCallback)(std::forward<EventParameterTypes>(params)...); };
return this->isListenerRegistered(bound);
}
bool isListenerRegistered(EventCallback eventCallback) {
return findListener(eventCallback) != this->m_eventCallbacks.cend();
}
void operator()(EventParameterTypes ... types) {
this->notify(std::forward<EventParameterTypes>(types)...);
}
void notify(EventParameterTypes ... types) {
for (const auto &it : this->m_eventCallbacks) {
if (it) (it)(std::forward<EventParameterTypes>(types)...);
}
}
private:
std::vector<EventCallback> m_eventCallbacks;
std::mutex m_eventListenerMutex;
typename std::vector<EventCallback>::const_iterator findListener(EventCallback eventCallback) {
for (auto iter = this->m_eventCallbacks.cbegin(); iter != this->m_eventCallbacks.cend(); iter++) {
if (getFunctionAddress(*iter) == getFunctionAddress(eventCallback)) {
return iter;
}
}
return this->m_eventCallbacks.cend();
}
Event &addEventCallback(EventCallback eventCallback) {
auto foundPosition = this->findListener(eventCallback);
if (foundPosition != this->m_eventCallbacks.cend()) {
return *this;
}
this->m_eventCallbacks.emplace_back(eventCallback);
return *this;
}
Event &removeEventCallback(EventCallback eventCallback) {
auto foundPosition = this->findListener(eventCallback);
if (foundPosition == this->m_eventCallbacks.cend()) {
return *this;
}
this->m_eventCallbacks.erase(foundPosition);
return *this;
}
};
#endif //EVENT_HPP
Related
As stated in an answer to this question, std::invoke handles calling not just of simple functions but also other callable types.
Unfortunately I am currently constrained to C++14 - so does anyone know of a C++14 compatible alternative?
My motivation:
My actual problem is that I am trying to write a simple wrapper for std::thread where I want to wrap the call of the passed function f with info like isRunning, which will be set to true before calling f(); and false afterwards.
One possible way I found, was to pass a member-method bound via std::bind(&Class::method, classInstance) - this however breaks the API, as this is something the user of my Wrapper class would have to do.
In case anyone is interested, here is my code:
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
class ThreadPeriodic : public std::thread
{
protected:
struct Settings
{
Settings(std::chrono::nanoseconds const periodDuration)
: isRunning(false)
, stopped(false)
, periodDuration(periodDuration)
{
}
volatile std::atomic<bool> isRunning;
std::mutex mutexStop;
std::condition_variable conditionVariableStop;
volatile std::atomic<bool> stopped;
std::chrono::nanoseconds const periodDuration;
};
std::shared_ptr<Settings> settings_;
template< class Function, class... Args >
class WrapperClass_
{
WrapperClass_() = delete;
public:
// https://stackoverflow.com/questions/34731367/how-to-pass-variadic-args-to-a-stdthread
static void wrapperMethod(std::shared_ptr<Settings> settings,
typename std::decay<Function>::type&& f,
typename std::decay<Args>::type&&... args)
{
settings->isRunning = true;
std::chrono::steady_clock::time_point nextPeriod = std::chrono::steady_clock::now();
bool stopped = settings->stopped.load();
while (!stopped)
{
try
{
f(std::forward<Args>(args)...);
}
catch (...)
{
// allthough this should never happen...
settings->isRunning = false;
throw;
}
nextPeriod += settings->periodDuration;
std::unique_lock<std::mutex> lock(settings->mutexStop);
stopped = settings->conditionVariableStop.wait_until(lock, nextPeriod, [settings](){return settings->stopped;});
}
settings->isRunning = false;
}
};
public:
ThreadPeriodic() noexcept
{
}
ThreadPeriodic(ThreadPeriodic && other) noexcept
{
operator=(std::move(other));
}
template< class Function, class... Args >
explicit ThreadPeriodic(std::chrono::nanoseconds const periodDuration, Function&& f, Args&&... args)
: settings_(std::make_shared<Settings>(periodDuration))
{
std::thread::operator=(std::thread(ThreadPeriodic::WrapperClass_<Function, Args...>::wrapperMethod,
settings_,
std::forward<Function>(f),
std::forward<Args>(args)...));
}
template< class Function, class... Args >
explicit ThreadPeriodic(Function&& f, Args&&... args)
: ThreadPeriodic(std::chrono::nanoseconds(0), std::forward<Function>(f), std::forward<Args>(args)...)
{
}
template< class Rep, class Period, class Function, class... Args >
explicit ThreadPeriodic(std::chrono::duration<Rep, Period> const periodDuration, Function&& f, Args&&... args)
: ThreadPeriodic(std::chrono::duration_cast<std::chrono::nanoseconds>(periodDuration), std::forward<Function>(f), std::forward<Args>(args)...)
{
}
ThreadPeriodic( const ThreadPeriodic& ) = delete;
ThreadPeriodic& operator=( ThreadPeriodic&& other ) noexcept
{
std::thread::operator=(std::move(other));
settings_ = std::move(other.settings_);
return *this;
}
bool isRunning() const
{
std::shared_ptr<Settings> settings = settings_;
return static_cast<bool>(settings) ? settings->isRunning.load() : false;
}
bool isStarted() const
{
std::shared_ptr<Settings> settings = settings_;
return static_cast<bool>(settings) && !settings->stopped;
}
bool isStopped() const
{
std::shared_ptr<Settings> settings = settings_;
return static_cast<bool>(settings) ? settings->stopped.load() : true;
}
// If joinNow is false, join() shall be called later on manually, as to ensure
// the thread is actually joined as it should.
void stop(bool const joinNow = true)
{
std::shared_ptr<Settings> settings = settings_;
if (!static_cast<bool>(settings))
{
throw std::logic_error("ThreadPeriodic::stop: this instance does not represent a thread.");
}
else if (settings->stopped)
{
throw std::logic_error("ThreadPeriodic::stop: this instance is already stopped.");
}
else
{
{
std::unique_lock<std::mutex> lock(settings->mutexStop);
settings->stopped = true;
}
settings->conditionVariableStop.notify_all();
if (joinNow && joinable())
{
join();
}
}
}
};
And if anyone wants to test it, here is a basic program:
#include <iostream>
class TestClass
{
public:
explicit TestClass(int const start = 0)
: start(start)
{
}
void printNumber(int const step = 1)
{
static int number = start;
std::cout << number << std::endl;
number += step;
}
int start;
};
int main()
{
TestClass testInstance(0);
// ThreadPeriodic thread(std::chrono::milliseconds(500), &TestClass::printNumber, testInstance, 3);
ThreadPeriodic thread(std::chrono::milliseconds(500), std::bind(&TestClass::printNumber, testInstance, std::placeholders::_1), 3);
std::this_thread::sleep_for(std::chrono::seconds(2));
thread.stop();
return 0;
}
I'm currently working on a project where a client part of my application has to be able to create custom templated classes on the server. The server part has to keep track of these created classes and has to remember the types with which the classes has been instantiated. The problem is, that there are around 36 different class-template-combinations that are valid in my application. I'm currently struggling to keep track of these different types in a collection without losing information about my instances.
I'm currently using something like this:
#include <memory>
#include <type_traits>
#include <vector>
enum class data_type : std::uint8_t {
type_int = 1,
type_float,
type_double
};
enum class class_type : std:: uint8_t {
type_A = 1,
type_B
};
struct X {
virtual data_type get_data_type() = 0;
virtual class_type get_class_type() = 0;
};
template <typename T>
struct A : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_A;
}
};
template <typename T>
struct B : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_B;
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
but I'm wondering if this is the way to go or if there is a more elegant way. Here I would have to always switch through the enums to get the full type out of my Storage class, something like:
switch(_classes.front()->get_class_type()) {
case class_type::type_A:
{
switch(_classes.front()->get_data_type()) {
case data_type::type_int:
{
/* I finally know that it is A<int> */
}
/* ... */
Thanks in advance.
You can consider using std::variant and the std::visit pattern
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit([](auto& value) {
using Type = std::decay_t<decltype(value)>;
if constexpr (std::is_same<Type, int>{}) {
// is an int
} else if (std::is_same<Type, float>{}) {
// is float
} else if (std::is_same<Type, double>{}) {
// is double
}
}, var);
If the if constexpr looks ugly to you then you can substitute it with a handrolled visitor class as well.
class Visitor {
public:
void operator()(int& value) { ... }
void operator()(float& value) { ... }
void operator()(double& value) { ... }
};
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit(Visitor{}, var);
As mentioned in the comments to the question, this is a viable approach that could help:
#include<vector>
#include<memory>
struct Counter {
static int next() {
static int v = 0;
return v++;
}
};
template<typename>
struct Type: Counter {
static int value() {
static const int v = Counter::next();
return v;
}
};
struct X {
virtual int get_data_type() = 0;
virtual int get_class_type() = 0;
};
template <typename T>
struct A : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<A<T>>::value();
}
};
template <typename T>
struct B : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<B<T>>::value();
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
int main() {
Storage s;
s.create<int, A>();
if(Type<int>::value() == s._classes.front()->get_class_type()) {
//...
};
}
See it running on wandbox.
I am working on a messaging system on C++. I have;
class MessageData
{
public:
typedef std::vector<std::shared_ptr<MessageData>> MessageList;
virtual int getValue(std::shared_ptr<int>) { throw "Not implemented!"; };
virtual float getValue(std::shared_ptr<float>) { throw "Not implemented!"; };
virtual std::string getValue(std::shared_ptr<std::string>) { throw "Not implemented!"; };
...
...
virtual ~MessageData() {};
};
template <typename T>
class Message : public MessageData
{
T val;
public:
static std::shared_ptr<Message<T>> Make(T val) { return std::make_shared<Message<T>>(val); };
static T Get(std::shared_ptr<MessageData> in) { return in->getValue(std::make_shared<T>()); };
Message(T i) { val = i; };
T getValue(std::shared_ptr<T> out) override { return *out = val; }
~Message() {};
};
Using these, I can send/receive generic messages of different length conveniently using e.g;
sendMessage(MessageData::MessageList{
Message<std::string>::Make("paint"),
Message<int>::Make(14),
Message<float>::Make(129.3f),
...
});
Then I get the values;
sendMessage(MessageData::MessageList data) {
auto a = Message<std::string>::Get(data[0]);
auto b = Message<int>::Get(data[1]);
auto c = Message<float>::Get(data[2]);
...
}
The downside is that I have to list all the types I need to use in MessageData class. This isn't a big deal as I can limit the types I want to support but I'm really curious about how to templatize the type list without using a 3rd party library. Or is there a completely different and better method that I can use with similar clean syntax and type safety to pass messages around?
One way to make your code more generic is:
template <typename ... Ts>
class MessageDataImp;
template <typename T>
class MessageDataImp<T>
{
public:
virtual ~MessageDataImp() = default;
virtual T getValue(std::shared_ptr<T>) { throw "Not implemented!"; };
};
template <typename T, typename ... Ts>
class MessageDataImp<T, Ts...> : public MessageDataImp<T>, public MessageDataImp<Ts...>
{
public:
using MessageDataImp<T>::getValue;
using MessageDataImp<Ts...>::getValue;
};
template <typename ... Ts>
class MessageDataTs : public MessageDataImp<Ts...>
{
public:
typedef std::vector<std::shared_ptr<MessageDataTs<Ts...>>> MessageList;
};
using MessageData = MessageDataTs<int, float, std::string>;
I think I've developed a decent solution to my problem.
class MessageData {
public:
typedef std::vector<std::shared_ptr<MessageData>> MessageList;
virtual ~MessageData() {};
};
template<typename T>
class Message : public MessageData {
T val;
public:
template<typename U>
friend U GetMessage(std::shared_ptr<MessageData> in);
Message(T i) { val = i; };
};
template<typename T>
T GetMessage(std::shared_ptr<MessageData> in) {
std::shared_ptr<Message<T>> tmp = std::dynamic_pointer_cast<Message<T>>(in);
if (tmp) {
return tmp->val;
}
throw "Incorrect type!";
};
template<typename T>
std::shared_ptr<Message<T>> MakeMessage(T val)
{
return std::make_shared<Message<T>>(val);
};
Then send & receive values using;
sendMessage(MessageData::MessageList{
MakeMessage(std::string("paint")),
MakeMessage(14),
MakeMessage(129.3f),
...
});
sendMessage(MessageData::MessageList data) {
auto a = GetMessage<std::string>(data[0]);
auto b = GetMessage<int>(data[1]);
auto c = GetMessage<float>(data[2]);
...
}
Assuming that it's a simple multiple-reader, multiple-writer message bus based on a non-prioritised queue, I think I'd start with something like this:-
Note that I have used boost::variant/optional. These could easily be replaced with std:: versions if you have those available.
I have used variant because it efficiently caters for most use cases with compile-time safety.
The std/boost::any version would require significant (and possibly unwelcome) care for users of your bus.
#include <iostream>
#include <string>
#include <queue>
#include <thread>
#include <condition_variable>
#include <boost/variant.hpp>
#include <boost/optional.hpp>
template<class Mutex> auto get_lock(Mutex& m) { return std::unique_lock<Mutex>(m); }
template<class...Types>
struct message_bus
{
using message_type = boost::variant<Types...>;
void push(message_type msg) {
auto lock = get_lock(mutex_);
messages_.push(std::move(msg));
lock.unlock();
activity_.notify_one();
}
boost::optional<message_type> wait_pop()
{
boost::optional<message_type> result;
auto lock = get_lock(mutex_);
activity_.wait(lock, [this] { return this->stopped_ or not this->messages_.empty(); });
if (not messages_.empty())
{
result = std::move(messages_.front());
messages_.pop();
}
return result;
}
void signal_stop()
{
auto lock = get_lock(mutex_);
stopped_ = true;
lock.unlock();
activity_.notify_all();
}
std::queue<message_type> messages_;
std::mutex mutex_;
std::condition_variable activity_;
bool stopped_ = false;
};
static std::mutex emit_mutex;
template<class T>
void emit(const T& t)
{
auto lock = get_lock(emit_mutex);
std::cout << std::this_thread::get_id() << ": " << t << std::endl;;
}
int main()
{
using bus_type = message_bus<std::string, int>;
bus_type mb;
std::vector<std::thread> threads;
for (int i = 0 ; i < 10 ; ++i)
{
threads.emplace_back([&]
{
for(;;)
{
auto message = mb.wait_pop();
if (not message)
break;
boost::apply_visitor([](auto&& data) { emit(data); }, message.value());
}
});
}
for (int i = 0 ; i < 1000 ; ++i)
{
mb.push("string: " + std::to_string(i));
mb.push(i);
}
mb.signal_stop();
for (auto& t : threads) if (t.joinable()) t.join();
}
I have some duplicated code in which I read from two streams,
{
std::ifstream ifs("A.dat");
... code ...
}
{
std::ifstream ifs("B.dat");
... same code ...
}
I wanted to unify both in one loop.
The first reaction is to do this:
for(auto ifs : {ifstream("A.dat"), ifstream("B.dat")})
{
... code ...
}
However it doesn't compile because the type is not copyable, so I tried this:
for(auto& ifs : {ifstream("A.dat"), ifstream("B.dat")})
{
... code ...
}
that doesn't work because ifs inside the loop is const. (a const ifstream cannot be used.)
This didn't work either, I think for the same reason:
for(auto&& ifs : {ifstream("A.dat"), ifstream("B.dat")})
At the end of course I ended up doing this.
#include<iostream>
int main(){
for(auto& name : {"A.dat", "B.dat"})
{
std::ifstream ifs(name);
... code ...
}
But I am still curious if it is possible to have range for-loop directly with a type like std::ifstream?
std::ifstream streams[2];
streams[0].open("A.dat");
streams[1].open("B.dat");
for (auto &stream:streams)
{
// ...
}
In c++, everything is possible.
Imagine being able to iterator a collection of any kind of stream, like this:
int main()
{
std::string buffer;
for (auto& stream : streams(std::istringstream("hello world"),
std::istringstream("funky chicken"),
std::ifstream("foo.txt")))
{
while (stream >> buffer)
{
std::cout << buffer << std::endl;
}
}
}
Well now you can. Behold: a polymorphic temporary container and iterator for any istream.
A similar technique will work for any arbitrary collection of objects that share a common polymorphic interface.
#include <iostream>
#include <fstream>
#include <sstream>
#include <utility>
#include <tuple>
#include <array>
namespace detail {
template<class Interface>
struct iface_iter
{
using value_type = Interface;
using reference = Interface&;
using internal_p = value_type * const *;
iface_iter(internal_p pp) : _pp(pp) {}
reference operator*() const {
return **_pp;
}
iface_iter& operator++() {
++_pp;
return *this;
}
bool operator==(const iface_iter& r) const {
return _pp == r._pp;
}
bool operator!=(const iface_iter& r) const {
return !(*this == r);
}
internal_p _pp;
};
template<class CommonType, class...Streams>
struct common_sequence
{
using common_type = CommonType;
using iterator = iface_iter<common_type>;
constexpr static std::size_t size() { return sizeof...(Streams); }
using storage_type = std::tuple<Streams...>;
using pointer_array = std::array<common_type*, size()>;
common_sequence(Streams...streams)
: _storage(std::move(streams)...)
, _pointers(build_pointers(std::make_index_sequence<size()>(), _storage))
{}
common_sequence(common_sequence&& r)
: _storage(std::move(r._storage))
, _pointers(build_pointers(std::make_index_sequence<size()>(), _storage))
{
}
common_sequence& operator=(common_sequence&& r)
{
_storage = std::move(r._storage);
_pointers = build_pointers(std::make_index_sequence<size()>(), _storage);
}
template<std::size_t I>
using stream_type = std::tuple_element_t<I, storage_type>;
template<std::size_t...Is>
static constexpr
pointer_array build_pointers(std::index_sequence<Is...>,
std::tuple<Streams...>& tup)
{
return pointer_array {
static_cast<common_type*>(&static_cast<stream_type<Is>&>(std::get<Is>(tup)))...
};
}
iterator begin() const {
return { _pointers.data() };
}
iterator end() const {
return { _pointers.data() + size() };
}
mutable storage_type _storage;
pointer_array _pointers;
};
}
template<class CommonBase, class...Things>
auto make_common_sequence(Things&&...ts)
{
return detail::common_sequence<CommonBase, std::decay_t<Things>...>(std::move(ts)...);
}
template<class...Streams>
auto streams(Streams&&...strs)
{
return make_common_sequence<std::istream>(std::move(strs)...);
}
struct base
{
virtual void foo() = 0;
};
struct d1 : base
{
void foo() override { std::cout << "d1::foo" << std::endl; }
};
struct d2 : base
{
void foo() override { std::cout << "d2::foo" << std::endl; }
};
template<class...Ts>
auto bases(Ts&&...ts)
{
return make_common_sequence<base>(std::move(ts)...);
}
int main()
{
std::string buffer;
for (auto& stream : streams(std::istringstream("hello world"),
std::istringstream("funky chicken"),
std::ifstream("foo.txt")))
{
while (stream >> buffer)
{
std::cout << buffer << std::endl;
}
}
for (auto& f : bases(d1(), d2(), d1(), d2()))
{
f.foo();
}
return 0;
}
expected output:
hello
world
funky
chicken
... plus whatever is in foo.txt ...
d1::foo
d2::foo
d1::foo
d2::foo
Of course, if we don't require polymorphism, a simple template variadic argument iterator will suffice:
template<class F, class...Things>
void apply_to_all(F f, Things... things)
{
using expand = int[];
void(expand{ 0,
(f(things), 0)...
});
}
int main()
{
std::string buffer;
apply_to_all([&](auto& stream)
{
while (stream >> buffer)
{
std::cout << buffer << std::endl;
}
},
std::istringstream("hello world"),
std::istringstream("funky chicken"),
std::ifstream("foo.txt"));
}
Inspired by #SamVarshavchik's answer I found that this works:
for (auto& ifs: std::array<std::ifstream, 2>{std::ifstream("A.dat"), std::ifstream("B.dat")} )
{
// ...
}
With std::make_array from TS2 (http://en.cppreference.com/w/cpp/experimental/make_array) this will work too:
for (auto& ifs: std::make_array(std::ifstream("A.dat"), std::ifstream("B.dat")) )
{
// ...
}
And with a further hack
template < class TT, class... Types>
constexpr std::array<TT, sizeof...(Types)> make_array_of(Types&&... t) {
return {TT(std::forward<Types>(t))... };
}
I can do
for (auto& ifs: make_array_of<std::ifstream>("A.dat", "B.dat") ){
...
}
I'm working on an embedded system, so code size is an issue. Using the standard library ups my binary size by about 60k, from 40k to 100k. I'd like to use std::function, but I can't justify it for 60k. Is there a standalone implementation that I can use, or something similar? I'm using it to implicitly cast lambdas in member functions with bound variables in c++ 11.
Here is simple implementation of std::function-like class template without inclusion of any headers. You can customize the behavior as you wish(like move/forward, empty call response, etc):
live_demo
// Scroll down for example of usage
namespace bicycle
{
template<typename Result,typename ...Args>
struct abstract_function
{
virtual Result operator()(Args... args)=0;
virtual abstract_function *clone() const =0;
virtual ~abstract_function() = default;
};
template<typename Func,typename Result,typename ...Args>
class concrete_function: public abstract_function<Result,Args...>
{
Func f;
public:
concrete_function(const Func &x)
: f(x)
{}
Result operator()(Args... args) override
{
return f(args...);
}
concrete_function *clone() const override
{
return new concrete_function{f};
}
};
template<typename Func>
struct func_filter
{
typedef Func type;
};
template<typename Result,typename ...Args>
struct func_filter<Result(Args...)>
{
typedef Result (*type)(Args...);
};
template<typename signature>
class function;
template<typename Result,typename ...Args>
class function<Result(Args...)>
{
abstract_function<Result,Args...> *f;
public:
function()
: f(nullptr)
{}
template<typename Func> function(const Func &x)
: f(new concrete_function<typename func_filter<Func>::type,Result,Args...>(x))
{}
function(const function &rhs)
: f(rhs.f ? rhs.f->clone() : nullptr)
{}
function &operator=(const function &rhs)
{
if( (&rhs != this ) && (rhs.f) )
{
auto *temp = rhs.f->clone();
delete f;
f = temp;
}
return *this;
}
template<typename Func> function &operator=(const Func &x)
{
auto *temp = new concrete_function<typename func_filter<Func>::type,Result,Args...>(x);
delete f;
f = temp;
return *this;
}
Result operator()(Args... args)
{
if(f)
return (*f)(args...);
else
return Result{};
}
~function()
{
delete f;
}
};
}
// ___________________[ Example of usage ]___________________ //
int func1(double)
{
return 1;
}
struct Functor2
{
int operator()(double)
{
return 2;
}
};
double func3(bool,int)
{
return 3.0;
}
struct Functor4
{
double operator()(bool,int)
{
return 4.0;
}
};
int main()
{
int res = 10;
{
bicycle::function<int(double)> f{func1};
res -= f(1.0);
f = Functor2{};
res -= f(2.0);
}
{
bicycle::function<double(bool,int)> f1;
f1 = func3;
bicycle::function<double(bool,int)> f2{f1};
res -= f2(true,1);
f1 = Functor4{};
f2 = f1;
res -= f2(false,2);
}
return res;
}
The 60k came from exception handling being added by the compiler, because exceptions were required for std::function. std::function only throws one exception, "bad_function_call". So I removed the code that threw the exception, now it seg faults if an empty function is called, and I saved myself 60k.