Suppose you have different predicates (function objects with initial state in this particular case) that you use with STL algorithms (copy_if ,sort etc...). Thing is that predicates can change at runtime by configuration change or user input. I've thought using polymorphism and virtual operator(), then settled on a std::function solution like this (this puts me in C++11 realm but that's okay)
struct PlainFilter {
PlainFilter(string filter):m_filter(filter)
{}
bool operator() (const string& toMatch)
{one way}
};
struct AcronymFilter {
AcronymFilter (string filter):m_filter(filter)
{}
bool operator() (const string& toMatch)
{a different way}
};
enum FilterTypes {plain,acronym};
vector<string> FilterStuff(string filter, vector<string> in)
{
vector<string> out;
std::function<bool(const string&)> foo;
if( filterType == plain)
foo = PlainFilter(filter);
else if( filterType == acronym)
foo = AcronymFilter(filter);
copy_if(in.begin(),in.end(),back_inserter(out),foo);
return out;
}
Is this good?
I'd rather avoid that if else statements everytime I need to filter strings since filter type might change once or none at all throughout the lifetime of the program.
Any other different take on the problem is also welcome..
There are probably several ways to do this, but this is what polymorphism is for. Your code is simplified, and you don't have to remember to add a new case or else if for any new filters you dream up in every place it could be used.
struct IFilter
{
virtual bool operator()(const std::string &) const = 0;
};
struct PlainFilter : public IFilter
{
virtual bool operator()(const std::string &filter) const override
{
// do something
}
};
struct AcronymFilter : public IFilter
{
virtual bool operator()(const std::string &filter) const override
{
// do something else
}
};
std::vector<std::string> FilterStuff(const IFilter &filter, const std::vector<std::string> &in)
{
std::vector<std::string> out;
std::copy_if(in.begin(), in.end(), std::back_inserter(out), filter);
return out;
}
However, I personally would implement FilterStuff differently. You're taking strings from one vector and copying them to another, and then presumably another piece of code is going to iterate over that new vector and do something with those filtered strings. Consider instead a design that takes a filter and the "do something with it" function:
void EnumerateStuff(const IFilter &filter, const std::vector<std::string> &in,
std::function<void(std::string)> callback)
{
for (const auto &s : in)
{
if (filter(s))
{
callback(s);
}
}
}
FilterStuff can now be written in terms of EnumerateStuff, if it's really necessary to have a filtered copy:
std::vector<std::string> FilterStuff(const IFilter &filter, const std::vector<std::string> &in)
{
std::vector<std::string> out;
EnumerateStuff(filter, in,
[&](const std::string &s)
{
out.push_back(s);
});
return out;
}
what is a filterType variable in your example? I guess some configurable parameter for your application/algorithm??
anyway, I'd propose the following:
1) collect all configurable parameters into a structure:
class configuration
{
public:
/// Type of predicate functor
typedef std::function<bool(const std::string&)> predicate_type;
struct plain_filter { /* your implementation */ };
struct acronym_filter { /* your implementation */ };
/// Type of predicate to use
enum class predicate_type { plain, acronym };
/// Set predicate
void set_filter_kind(const predicate_type ft)
{
switch (ft)
{
case predicate_type::plain:
m_predicate = plain_filter();
break;
case predicate_type::acronym:
m_predicate = acronym_filter();
break;
default:
assert(!"Invalid filter type");
}
}
/// Get filter to be used by algorithms
/// \todo Consider to return a const reference instead of copy,
/// but make sure your filters are state-less (as expected by STL slgorithms)
decltype(m_predicate) use_filter() const
{
return m_predicate;
}
// other configuration parameters/methods
private:
predicate_type m_predicate;
};
2) fill an instance of configuration from command-line options, config file, or user input. Make this instance visible to all required parts of your code (for example make it the member of your application class and provide a method to (read-only) access it or smth like this...)
3) use configuration data in your algorithms
std::vector<string> filter_stuff(string filter, const std::vector<string>& in)
{
std::vector<string> out;
std::copy_if(
begin(in)
, end(in)
, std::back_inserter(out)
, application().get_config().use_filter()
);
return out;
}
PS: btw, pass in parameter via reference (or rvalue reference)... I'm really in doubt that you need a copy (pass it by value)
Since filterType is a runtime value, you're going to have some kind of selection going on here. There's your if's, a switch, or an array lookup. I like the switch best, the array lookup requires more complex types and isn't any faster once the optimizer gets through with it. Also I'd pass the initializers by const & not by value just on reflex.
That said, I think your method's fine. Another way to do it:
bool plain_string_test(const string& filter, const string& candidate)
{ /* ... one way ... */ }
bool acronym_string_test(const string& filter, const string& candidate)
{ /* ... or another ... */ }
enum FilterTypes {plain,acronym};
vector<string> FilterStuff(string filter, vector<string> in)
{
vector<string> out;
std::function<bool(const string&, const string&)> filtermethod;
switch(filterType) {
default: throw some_domain_error(some_constructor_here);
case plain: filtermethod = plain_string_test; break;
case acronym: filtermethod = acronym_string_test; break;
}
copy_if(in.begin(),in.end(),back_inserter(out),
[&filtermethod, &filter](const string& candidate) -> bool
{ return filtermethod(filter,candidate); }
return out;
}
I do like this one better; it eliminates some type scaffolding and some copying and makes the string tests more reusable (or also elminates some function scaffolding). Here you might be able to get better value from a static array of functions, it'd probably depend on context.
keyboard-to-editbox warning, I haven't tested this code but I do believe it's at least correct enough for communication.
Related
Let's see a real life example:
class RuleNameConverter {
public:
RuleNameConverter(const boost::property_tree::ptree& pt);
int toIdentifier(const std::string& name) const;
std::string toName(const int id) const;
private:
using Bimap = boost::bimap<std::string, int>;
Bimap bimap_;
};
Where the constructor is this:
RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) {
for (const auto& item : pt) {
if (item.first == "rule") {
auto name = item.second.get < std::string > ("<xmlattr>.name");
auto id = item.second.get<int>("<xmlattr>.id");
bimap_.insert(Bimap::value_type { name, id });
}
}
}
Assume you want a const member attribute:
...
const Bimap bimap_;
};
You must initialize it in the initializer list, not in the constructor body. It's initialization is non trivial, so you must delegate a function to compute its value. You can use the value returned by a lambda, taking advantages of the move semantics (no copy of temporary objects):
RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) :
bimap_ { [&pt]() {
Bimap results;
for (const auto& item : pt) {
if (item.first == "rule") {
auto name = item.second.get < std::string > ("<xmlattr>.name");
auto id = item.second.get<int>("<xmlattr>.id");
results.insert(Bimap::value_type {name, id});
}
}
return results;
}() } {
}
Are there any drawbacks to using this technique? Is it worth the trouble? I find it slightly less readable, but what about performance?
Performance-wise, it should not matter all that much. You don't copy around any Bitmap objects, and the construction of your lambda should not take any noticeable time.
But for readability, I would create a static member function instead of a lambda here:
class RuleNameConverter {
public:
RuleNameConverter(const boost::property_tree::ptree& pt);
private:
static Bitmap createBitmap(const boost::property_tree::ptree& pt);
};
RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) :
bimap_ { createBitmap(pt) } {
}
Bitmap RuleNameConverter::createBitmap(const boost::property_tree::ptree& pt) {
Bimap results;
for (const auto& item : pt) {
if (item.first == "rule") {
auto name = item.second.get < std::string > ("<xmlattr>.name");
auto id = item.second.get<int>("<xmlattr>.id");
results.insert(Bimap::value_type {name, id});
}
}
return results;
}
When you need to initialise several members using helper functions, creating a new lambda for each member leads to an unmaintainable mess in the constructor initialiser list, but several helper functions don't need to have that problem. Additionally, if you add constructor overloads, createBitmap can be easily called from multiple constructors.
Alternatively, use a regular non-member function if the body of createBitmap is not really specific to your RuleNameConverter.
You could wrap the Bimap in another class, where its constructor would have the exact same body as the lambda.
I can't see how using a lambda to avoid a superficial class in this case would lead to any problems, except its intent is perhaps less clear, because it doesn't have a name (but that's the case with pretty much any lambda).
In a C++ project I'm working on, I need to keep track of a label. The label simply stores a std::string that is appended to results written to various files so that the results can be mapped to a particular phase of the implemented algorithms.
Here are the requirements of the mechanism for keeping track of the label:
All translation units need access to this label
Label must be able to be modified during runtime
Need to control access to the label via getter/setter functions
Always need exactly 1 label
This is not hard to implement. But, nonetheless, I'm raising the question here because I suspect this is something commonly done --- or, at least, very similar to things commonly done.
The best solution I can think of is to have a class such as the following, and then just include the interface everywhere:
class Label {
public:
static std::string get();
static int set(std::string s);
private:
static std::string label;
};
std::string Label::get() { return label; }
int Label::set(std::string s) {
if( /* OK to change to "s" */ ) {
label = s;
return 0;
}
return 1;
}
std::string Label::label = "";
Because there's always exactly 1 of these labels, it seems like there ought to be a better solution than creating a class. Any suggestions?
I'd tend to wonder whether there might not be more use for a broader class, something like:
template <class T>
class cond_write {
T val;
std::function<bool()> c;
public:
template <class Cond>
cond_write(T const &t, Cond c): val(t), c(c) {}
cond_write &operator=(T const &t) {
if (c())
val=t;
return *this;
}
operator T() const { return val; }
};
Then you'd instantiate it with (in your case) std::string, and a lambda for the condition under which a write can happen.
Instead of get and set, you'd just assign to it, or use it as a T (std::string, in your case). For example:
cond_write<std::string> label("Initial label", []() { return whatever(); });
// equivalent to label.set("This might be the new label");
label="This might be the new label";
// equivalent to std::string new_label = label.get();
std::string new_label=label;
I see no need for a class here and recommend using free functions and a namespace. You have the same scoping semantics but without all of the decorations such as static. They also allow you to keep internals private just as you would with a class. A few minor changes and your code ends up like the following.
Header
namespace Label
{
std::string get();
// only require a copy when necessary and allow rvalues.
int set(const std::string& s);
};
Implementation
namespace // unnamed namespace is generally recommended over using static
{
std::string label;
}
std::string Label::get() { return label; }
int Label::set(const std::string& s)
{
if( /* OK to change to "s" */ )
{
label = s;
return 0;
}
return 1;
}
In C++, I have an class which is ordered by its name which is a std::string. I wish to only have one per each unique name in either a std::map or std::set.
I could use a std::set since the operator< will order my instances by their name, however, I need to lookup an instance by its name. Using a map where the key is the name is straight forward, however, I could also use a set and construct a dummy instance of my class with the name I wish to lookup to locate in the set the actual instance of the class for the given name.
I imagine I should just go with the map to make the code straight forward, but wonder if there might be a way to go with the set since the key is effectively part of my object anyway and thus avoid some redundancy.
Is there a way to use the set and be able to locate objects by their key in a clean way or should I just use a map and be done with it?
Here is the class to be inserted (in draft form) and in each directory there is either a set or map of Node(s) keyed off the Node's name:
class Node {
public:
Node(Directory &parent, const std::string &name)
: _name(name),
_parent(&parent),
_isRoot(false) {
if (name.empty()) {
throw InvalidNodeNameError(name);
}
}
protected:
// This is only used for the root directory:
Node()
: _name(""),
_parent(0),
_isRoot(true) {
}
Node(const std::string &name)
: _name(name),
_parent(0),
isRoot(false) {
}
public:
virtual ~Node() {
if (parent()) {
parent()->remove(*this);
}
}
bool operator<(const Node &rhs) const {
return _name < rhs._name;
}
Directory *parent() const {
return _parent;
}
void setParent(Directory *parent) {
_parent = parent;
}
const std::string &name() const {
return _name;
}
bool isRoot() const {
return _isRoot;
}
std::string pathname() const {
std::ostringstream path;
if (parent()) {
path << parent()->pathname() << '/';
} else {
path << '/';
}
path << name();
return path.str();
}
private:
// Not defined:
Node(const Node &rhs);
Node &operator=(const Node &rhs);
private:
std::string _name;
Directory *_parent;
const bool _isRoot;
};
Actually, you can just use map<std::string&, Node>, at the cost of one extra pointer, but I think you probably knew that, and it requires some mucking about to get what you want.
I've always thought it was a real pain that std::set didn't come with an explicit KeyExtractor template parameter, particularly since every implementation I've seen uses one of those under the hood in order to not duplicate code between (multi)maps and (multi)sets. Here's a quick and dirty hack, not close to complete, which exposes some of the mechanics of the GNU standard C++ library in order to create a "keyed_set" container:
// Deriving from the tree is probably not a good idea, but it was easy.
template<typename Key, typename Val, typename Extract,
typename Compare = std::less<Key>, typename Alloc = std::allocator<Val>>
class keyed_set : public std::_Rb_tree<Key, Val, Extract, Compare, Alloc> {
using Base = std::_Rb_tree<Key, Val, Extract, Compare, Alloc>;
public:
template<typename ...Args>
auto insert(Args... args)
->decltype(Base()._M_insert_unique(std::declval<Args>()...)) {
return this->_M_insert_unique(args...);
}
typename Base::iterator insert(typename Base::const_iterator i,
const Val& val) {
return this->_M_insert_unique_(i, val);
}
Val& operator[](const Key& key) {
auto i = this->lower_bound(key);
if (i == this->end() || this->key_comp()(key, Extract()(*i))) {
i = this->_M_insert_unique_(i, Val(key));
}
return *i;
}
};
To make this work, you need to provide a Key Extractor, like this:
template<class T>
struct KeyExtractor;
template<>
struct KeyExtractor<Node> {
const std::string& operator()(const Node& n) { return n.name(); }
};
To get my version of operator[] to work, you need the value type to have a constructor which takes its key type as an argument.
I left out lots of stuff (erase, for example); but it was good enough to do a simple test.
It would probably have been better to default the key type from the return type of the KeyExtractor, but that would have involved putting the template arguments in a different order, and I already wasted too much time not noticing that _M_insert_unique and _M_insert_unique_ are spelled differently (presumably to avoid template instantiation problems.)
Here's the example I used to check to make sure that works; MyKeyedClass has a name, with a vector of strings, and a double associated with each one. (There's no sublime purpose.)
int main(void) {
keyed_set<std::string, MyKeyedClass, KeyExtractor<MyKeyedClass>> repo;
for (std::string name, val; std::cin >> name >> val; ) {
try {
size_t end;
double d = std::stod(val, &end);
if (end != val.size())
throw std::invalid_argument("trailing letters");
repo[name].increment(d);
} catch (std::invalid_argument(e)) {
repo[name].push(val);
} catch (std::out_of_range(e)) {
std::cerr << "You managed to type an out of range double" << std::endl;
}
}
std::for_each(repo.begin(), repo.end(),
[](MyKeyedClass& c){ std::cout << c << std::endl; });
return 0;
}
I think that because Node requires a reference to Directory during construction, making a dummy node to search your set by name will make the Node class more cluttered.
To use set you'd probably need to make a static Directory somewhere, and use that as a dummy reference in a new dummy constructor Node(const std::string&). If you don't declare that explicit you can use a string directly in your call to set::find.
You could instead convert the class to use pointers... But that would change its internal semantics: Directory& is always valid, whereas Directory* doesn't have to be. Ask yourself whether you want to make the semantics less clear to the reader simply because of your preference for the set container.
So my opinion is pretty clear in this case... You have a choice: Either use map and keep your class clean, or use set and write a bit of supporting junk code that has no use for anything else. =)
I implement such classes through a proxy for key, for example in case of std::string I have a class called lightweight_string, that implement operator < and internally it point to an std::string then I use map and have both simplicity of using map and performance of not having 2 version of key.
For your very case check if your compiler is old enough to still implement std::string with COW (copy on write) strategy. This changed in C++11, but old compiler versions still are COWs... This has the advantage that it will cost you almost nothing to have map with string as key and as part of value. But be aware this will change in future (or already changed)...
So I want to create a simple map std::map<T1, std::string> and I have a function that returns std::string I want somehow to link item creation in std::map with my function so that when my_map[some_new_element] is called my function will be called and its return set to value for some_new_element key. Is such thing possible and how to do it?
You can wrap the map itself or the value type or operator[].
Last wrapper will be the simplest:
template <typename T>
std::string& get_default(std::map<T, std::string>& map, const T& key) {
auto it = map.find(key);
if (it == map.end()) {
return map[key] = create_default_value();
} else {
return *it;
}
}
The value type shouldn't be too hard, either:
struct default_string {
std::string wrapped_string;
default_string() : wrapped_string(create_default_value()) {}
explicit default_string(const std::string& wrapped_string)
: wrapped_string(wrapped_string) {}
operator const std::string&() const { return wrapped_string; }
operator std::string&() { return wrapped_string; }
};
Wrapping map will take a bit more work, as you'd have to duplicate the entire interface, including typedefs. Note: this code is not tested, treat it as proof-of-concept, to steer you in the right direction.
What about a small wrapper class for std::string?
class StringWrapper {
StringWrapper() { //... your code
}
operator std::string&() { return m_string; } // or something like that
private:
std::string m_string;
};
Now you use the following map-type:
std::map<T1, StringWrapper> mymap;
In the constructor of StringWrapper you can define custom actions. It gets called when you insert an item into your map.
I was searching for an implementation of extension methods in c++ and came upon this comp.std.c++ discussion which mentions that polymorphic_map can be used to associated methods with a class, but, the provided link seems to be dead. Does anyone know what that answer was referring to, or if there is another way to extend classes in a similar manner to extension methods (perhaps through some usage of mixins?).
I know the canonical C++ solution is to use free functions; this is more out of curiosity than anything else.
Different languages approach development in different ways. In particular C# and Java have a strong point of view with respect to OO that leads to everything is an object mindset (C# is a little more lax here). In that approach, extension methods provide a simple way of extending an existing object or interface to add new features.
There are no extension methods in C++, nor are they needed. When developing C++, forget the everything is an object paradigm --which, by the way, is false even in Java/C# [*]. A different mindset is taken in C++, there are objects, and the objects have operations that are inherently part of the object, but there are also other operations that form part of the interface and need not be part of the class. A must read by Herb Sutter is What's In a Class?, where the author defends (and I agree) that you can easily extend any given class with simple free functions.
As a particular simple example, the standard templated class basic_ostream has a few member methods to dump the contents of some primitive types, and then it is enhanced with (also templated) free functions that extend that functionality to other types by using the existing public interface. For example, std::cout << 1; is implemented as a member function, while std::cout << "Hi"; is a free function implemented in terms of other more basic members.
Extensibility in C++ is achieved by means of free functions, not by ways of adding new methods to existing objects.
[*] Everything is not an object.
In a given domain will contain a set of actual objects that can be modeled and operations that can be applied to them, in some cases those operations will be part of the object, but in some other cases they will not. In particular you will find utility classes in the languages that claim that everything is an object and those utility classes are nothing but a layer trying to hide the fact that those methods don't belong to any particular object.
Even some operations that are implemented as member functions are not really operations on the object. Consider addition for a Complex number class, how is sum (or +) more of an operation on the first argument than the second? Why a.sum(b); or b.sum(a), should it not be sum( a, b )?
Forcing the operations to be member methods actually produces weird effects --but we are just used to them: a.equals(b); and b.equals(a); might have completely different results even if the implementation of equals is fully symmetric. (Consider what happens when either a or b is a null pointer)
Boost Range Library's approach use operator|().
r | filtered(p);
I can write trim for string as follows in the same way, too.
#include <string>
namespace string_extension {
struct trim_t {
std::string operator()(const std::string& s) const
{
...
return s;
}
};
const trim_t trim = {};
std::string operator|(const std::string& s, trim_t f)
{
return f(s);
}
} // namespace string_extension
int main()
{
const std::string s = " abc ";
const std::string result = s | string_extension::trim;
}
This is the closest thing that I have ever seen to extension methods in C++. Personally i like the way it can be used, and possibly this it the closest we can get to extension methods in this language. But there are some disadvantages:
It may be complicated to implement
Operator precedence may be not that nice some times, this may cause surprises
A solution:
#include <iostream>
using namespace std;
class regular_class {
public:
void simple_method(void) const {
cout << "simple_method called." << endl;
}
};
class ext_method {
private:
// arguments of the extension method
int x_;
public:
// arguments get initialized here
ext_method(int x) : x_(x) {
}
// just a dummy overload to return a reference to itself
ext_method& operator-(void) {
return *this;
}
// extension method body is implemented here. The return type of this op. overload
// should be the return type of the extension method
friend const regular_class& operator<(const regular_class& obj, const ext_method& mthd) {
cout << "Extension method called with: " << mthd.x_ << " on " << &obj << endl;
return obj;
}
};
int main()
{
regular_class obj;
cout << "regular_class object at: " << &obj << endl;
obj.simple_method();
obj<-ext_method(3)<-ext_method(8);
return 0;
}
This is not my personal invention, recently a friend of mine mailed it to me, he said he got it from a university mailing list.
The short answer is that you cannot do that. The long answer is that you can simulate it, but be aware that you'll have to create a lot of code as workaround (actually, I don't think there is an elegant solution).
In the discussion, a very complex workaround is provided using operator- (which is a bad idea, in my opinion). I guess that the solution provided in the dead link was more o less similar (since it was based on operator|).
This is based in the capability of being able to do more or less the same thing as an extension method with operators. For example, if you want to overload the ostream's operator<< for your new class Foo, you could do:
class Foo {
friend ostream &operator<<(ostream &o, const Foo &foo);
// more things...
};
ostream &operator<<(ostream &o, const Foo &foo)
{
// write foo's info to o
}
As I said, this is the only similar mechanism availabe in C++ for extension methods. If you can naturally translate your function to an overloaded operator, then it is fine. The only other possibility is to artificially overload an operator that has nothing to do with your objective, but this is going to make you write very confusing code.
The most similar approach I can think of would mean to create an extension class and create your new methods there. Unfortunately, this means that you'll need to "adapt" your objects:
class stringext {
public:
stringext(std::string &s) : str( &s )
{}
string trim()
{ ...; return *str; }
private:
string * str;
};
And then, when you want to do that things:
void fie(string &str)
{
// ...
cout << stringext( str ).trim() << endl;
}
As said, this is not perfect, and I don't think that kind of perfect solution exists.
Sorry.
To elaborate more on #Akira answer, operator| can be used to extend existing classes with functions that take parameters too. Here an example that I'm using to extend Xerces XML library with find functionalities that can be easily concatenated:
#pragma once
#include <string>
#include <stdexcept>
#include <xercesc/dom/DOMElement.hpp>
#define _U16C // macro that converts string to char16_t array
XERCES_CPP_NAMESPACE_BEGIN
struct FindFirst
{
FindFirst(const std::string& name);
DOMElement * operator()(const DOMElement &el) const;
DOMElement * operator()(const DOMElement *el) const;
private:
std::string m_name;
};
struct FindFirstExisting
{
FindFirstExisting(const std::string& name);
DOMElement & operator()(const DOMElement &el) const;
private:
std::string m_name;
};
inline DOMElement & operator|(const DOMElement &el, const FindFirstExisting &f)
{
return f(el);
}
inline DOMElement * operator|(const DOMElement &el, const FindFirst &f)
{
return f(el);
}
inline DOMElement * operator|(const DOMElement *el, const FindFirst &f)
{
return f(el);
}
inline FindFirst::FindFirst(const std::string & name)
: m_name(name)
{
}
inline DOMElement * FindFirst::operator()(const DOMElement &el) const
{
auto list = el.getElementsByTagName(_U16C(m_name));
if (list->getLength() == 0)
return nullptr;
return static_cast<DOMElement *>(list->item(0));
}
inline DOMElement * FindFirst::operator()(const DOMElement *el) const
{
if (el == nullptr)
return nullptr;
auto list = el->getElementsByTagName(_U16C(m_name));
if (list->getLength() == 0)
return nullptr;
return static_cast<DOMElement *>(list->item(0));
}
inline FindFirstExisting::FindFirstExisting(const std::string & name)
: m_name(name)
{
}
inline DOMElement & FindFirstExisting::operator()(const DOMElement & el) const
{
auto list = el.getElementsByTagName(_U16C(m_name));
if (list->getLength() == 0)
throw runtime_error(string("Missing element with name ") + m_name);
return static_cast<DOMElement &>(*list->item(0));
}
XERCES_CPP_NAMESPACE_END
It can be used this way:
auto packetRate = *elementRoot | FindFirst("Header") | FindFirst("PacketRate");
auto &decrypted = *elementRoot | FindFirstExisting("Header") | FindFirstExisting("Decrypted");
You can enable kinda extension methods for your own class/struct or for some specific type in some scope. See rough solution below.
class Extensible
{
public:
template<class TRes, class T, class... Args>
std::function<TRes(Args...)> operator|
(std::function<TRes(T&, Args...)>& extension)
{
return [this, &extension](Args... args) -> TRes
{
return extension(*static_cast<T*>(this), std::forward<Args>(args)...);
};
}
};
Then inherit your class from this and use like
class SomeExtensible : public Extensible { /*...*/ };
std::function<int(SomeExtensible&, int)> fn;
SomeExtensible se;
int i = (se | fn)(4);
Or you can declare this operator in cpp file or namespace.
//for std::string, for example
template<class TRes, class... Args>
std::function<TRes(Args...)> operator|
(std::string& s, std::function<TRes(std::string&, Args...)>& extension)
{
return [&s, &extension](Args... args) -> TRes
{
return extension(s, std::forward<Args>(args)...);
};
}
std::string s = "newStr";
std::function<std::string(std::string&)> init = [](std::string& s) {
return s = "initialized";
};
(s | init)();
Or even wrap it in macro (I know, it's generally bad idea, nevertheless you can):
#define ENABLE_EXTENSIONS_FOR(x) \
template<class TRes, class... Args> \
std::function<TRes(Args...)> operator| (x s, std::function<TRes(x, Args...)>& extension) \
{ \
return [&s, &extension](Args... args) -> TRes \
{ \
return extension(s, std::forward<Args>(args)...); \
}; \
}
ENABLE_EXTENSIONS_FOR(std::vector<int>&);
This syntactic sugar isn't available in C++, but you can define your own namespace and write pure static classes, using const references as the first parameter.
For example, I was struggling using the STL implementation for some array operations, and I didn't like the syntaxis, I was used to JavaScript's functional way of how array methods worked.
So, I made my own namespace wh with the class vector in it, since that's the class I was expecting to use these methods, and this is the result:
//#ifndef __WH_HPP
//#define __WH_HPP
#include <vector>
#include <functional>
#include <algorithm>
namespace wh{
template<typename T>
class vector{
public:
static T reduce(const std::vector<T> &array, const T &accumulatorInitiator, const std::function<T(T,T)> &functor){
T accumulator = accumulatorInitiator;
for(auto &element: array) accumulator = functor(element, accumulator);
return accumulator;
}
static T reduce(const std::vector<T> &array, const T &accumulatorInitiator){
return wh::vector<T>::reduce(array, accumulatorInitiator, [](T element, T acc){return element + acc;});
}
static std::vector<T> map(const std::vector<T> &array, const std::function<T(T)> &functor){
std::vector<T> ret;
transform(array.begin(), array.end(), std::back_inserter(ret), functor);
return ret;
}
static std::vector<T> filter(const std::vector<T> &array, const std::function<bool(T)> &functor){
std::vector<T> ret;
copy_if(array.begin(), array.end(), std::back_inserter(ret), functor);
return ret;
}
static bool all(const std::vector<T> &array, const std::function<bool(T)> &functor){
return all_of(array.begin(), array.end(), functor);
}
static bool any(const std::vector<T> &array, const std::function<bool(T)> &functor){
return any_of(array.begin(), array.end(), functor);
}
};
}
//#undef __WH_HPP
I wouldn't inherit nor compose a class with it, since I've never been able to do it peacefully without any side-effects, but I came up with this, just const references.
The problem of course, is the extremely verbose code you have to make in order to use these static methods:
int main()
{
vector<int> numbers = {1,2,3,4,5,6};
numbers = wh::vector<int>::filter(numbers, [](int number){return number < 3;});
numbers = wh::vector<int>::map(numbers,[](int number){return number + 3;});
for(const auto& number: numbers) cout << number << endl;
return 0;
}
If only there was syntactic sugar that could make my static methods have some kind of more common syntax like:
myvector.map([](int number){return number+2;}); //...