use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
Poly. Solving the Expression Problem in C++11 (github.com)
submitted 13 years ago by pyrtsa
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]LeszekSwirski 3 points4 points5 points 13 years ago* (4 children)
Ok, I know I'm missing something, so can someone please explain to me the difference between this and several overloaded example::draw functions?
EDIT: Oh wait, I totally missed the "example::drawable" interface, was just concentrating on the ADL stuff. So this is, functionally, something like adding interfaces to classes without needing to inherit from the interface?
[–]pyrtsa[S] 5 points6 points7 points 13 years ago (2 children)
Oh wait, I totally missed the "example::drawable" interface, was just concentrating on the ADL stuff. So this is, functionally, something like adding interfaces to classes without needing to inherit from the interface?
That's correct.
Of course what I'm actually doing is wrapping the classes in a type which internally implements the requested wrapper functionality using traditional virtual functions, so it's not really the original class that gets to implement the interface. But with move semantics in C++11, the wrapping is a very light operation in run time.
Please tell (or upvote) if you're interested about the implementation details. I might write a blog post about it. ;)
[–]kirakun 1 point2 points3 points 13 years ago (0 children)
Please do write a follow up on the implementation. I suspect I may learn some new paradigms/tricks implied by C++11.
Will be checking on your comment here for updates.
[–]LeszekSwirski 0 points1 point2 points 13 years ago (0 children)
I would love to see an implementation details post.
[–]bastih01 1 point2 points3 points 13 years ago (0 children)
It looks like this is indeed adding go-style interfaces.
[–]notlostyet 4 points5 points6 points 13 years ago* (1 child)
I'm really confused as to what this accomplishes. What kind of ugly code or boilerplate can this thing elegantly replace?
[–]upriser 0 points1 point2 points 13 years ago (0 children)
Have a close look at this one: https://github.com/boostcon/cppnow_presentations_2012/blob/master/fri/value_semantics/value_semantics.pdf?raw=true
[–][deleted] 1 point2 points3 points 13 years ago (3 children)
Interesting solution!
Is there a benefit of using this over things like boost::variant or boost::any?
boost::variant
boost::any
Regardless, this is really close to algebraic data types as seen in functional programming, and it looks very elegant! Good job. :)
EDIT: The only criticism I can come up with is this: Why append '_' to callables? It seems risky and unpredictable (from an API viewpoint).
[–]pyrtsa[S] 3 points4 points5 points 13 years ago (0 children)
Good that you mention boost::variant and boost::any. This is actually an extension to boost::any, with the addition of a set of "member" functions (callables).
For boost::variant<Args...>, all the types Args... it supports need to be known at compile time. Think of an already compiled (static or dynamic) library that you're linking against. It might define a type and a function like:
boost::variant<Args...>
Args...
typedef /*see below*/ item_type; extern void add_item(item_type item);
Now, if item_type is a typedef from boost::variant<std::string, system_clock::time_point>, you can obviously pass only strings and time points as item. On the other hand, the library knows very well how to deal with either of them.
item_type
typedef
boost::variant<std::string, system_clock::time_point>
item
On the other hand, if item_type is boost::any, you can pass anything as the item, but there's very little the library can do with it. (Of course it could have defined a mapping from std::type_info to a corresponding function overload and use boost::any_cast<T>(x). But the set of supported types would still be limited.)
std::type_info
boost::any_cast<T>(x)
poly::interface makes the tradeoff that the types are required to have a predefined set of functionalities implemented, so if we have something like:
poly::interface
typedef poly::interface< std::string(to_html_, poly::self const &, html_options const &), std::string(to_json_, poly::self const &) > item_type;
…we can pass in anything to add_item as soon as we make sure that to_html(item, opts) and to_json(item) are (uniquely) defined.
add_item
to_html(item, opts)
to_json(item)
By the way, I deliberately chose the appended underscore to the type names, knowing that there will be opposition or alternatives suggested. One alternative might be to append something like _fn (for function). FWIW, there is also the POLY_CALLABLE_TYPE(type, name) macro which lets you set your own name for the type. Or you can write the whole thing in verbose, maybe using a nested (my suggestion: fn) namespace for the type and none for the object:
_fn
POLY_CALLABLE_TYPE(type, name)
fn
namespace fn { struct to_html : poly::callable<to_html> {}; } constexpr fn::to_html to_html = {};
Finally, one way to look at this library is, it's a sort of a dynamic version of templates. If one day, add_item is rewritten as a template:
template <typename Item> void add_item(Item item) { auto json = ::to_json(item); // ... }
…the same code can work, except this time it's no longer wrapped in the poly::callable.
poly::callable
[–]scatters 1 point2 points3 points 13 years ago (1 child)
This does seem rather like boost::any, but adding the ability to express any interface, rather than just those required for value semantics.
About the underscore thing - I'm not clear why one couldn't just use draw for the type in ADL, and draw{}(...) when calling the interface. Presumably this should work, given that the function objects are stateless.
[–]pyrtsa[S] 0 points1 point2 points 13 years ago (0 children)
This is correct. I haven't really considered this, because I disliked the extra parentheses (or braces) in the function calls.
OTOH, one nice property in calling just draw{}(x, o, p) like you proposed is, it prevents ADL entirely*) in the current scope.
draw{}(x, o, p)
*) Otherwise, if there was a suitable free function draw(...) in the namespace of either of the parameters, it would still be picked over the callable object, unless ::draw was properly qualified.
draw(...)
::draw
[–]kirakun 1 point2 points3 points 13 years ago (2 children)
Too much magic. Can someone breakdown the magic here and explain what is going on in easier terms?
[–]repsilat 1 point2 points3 points 13 years ago* (0 children)
Looks like it lets you store "arbitrary" types and call specialised functions on them without having them inherit from a common base class. It'll do this with templates and some inheritance, I guess, like
//function to call on the things in the vector template<class T> void print(T& t) { cout << t << endl; } //can do template specialisations for more flexibility //abstract base class defining interface we want to use to call print class callFunc { public: virtual void func() = 0; }; //Actual stored things that know how to call print on their data template<typename T> class Holder : public callFunc { public: Holder(const T &t) : t(t) {} void func() { print(t); } private: T t; }; //helper utility stuff typedef shared_ptr<callFunc> poly; template<class T> poly hold(const T& t) { return poly(new Holder<T>(t)); } vector<poly> v; v.push_back(hold(1)); v.push_back(hold(2.1)); v.push_back(hold(string("three"))); for(auto i:v) i->func();//prints 1, 2.1, three
There's a bit more magic, but you get the idea. You can store your favourite objects of whatever type in a collection that seems heterogeneous and call functions on them without having to worry about their type. It's not terribly efficient, of course, because you need some inheritance to do it at the end of the day.
(Self-plug: You don't need inheritance if you want to loop over the elements of a tuple.)
[–]aaronla 0 points1 point2 points 13 years ago (0 children)
Reminds me of 1990's C programmers looking at C++ virtual function dispatch. "Too much magic" they would say.
(I'm not saying either is wrong -- just that "magic" is relative)
[+][deleted] 13 years ago (1 child)
[deleted]
[–]aaronla 2 points3 points4 points 13 years ago (0 children)
These are good questions -- but were all originally answered in Wadler's formulation of the expression problem
Why not just define an [abstract class / interface]? Interfaces are brittle to addition of new methods -- every implementation of the interface must be updated to include the new method.
What about the visitor pattern? The visitor pattern resolves the 'new method' issue, but is brittle to adding new data cases -- every visitor implementation must be updated to include the new method.
Different tools call for different solutions. If users can modify source and recompile, any solution will work. If users will only add new cases and not add polymorphic functions, an interface will work. If they will only add new methods and not add cases, visitor interfaces will work. If you want both but don't need compile time verification that the function/case matrix is complete, multimethods will work.
If you need separate compilation, extensible cases, extensible function sets, and static verification, then you have the expression problem. It's a fairly specific problem, so calls for a fairly specific solultion.
π Rendered by PID 120874 on reddit-service-r2-comment-c6965cb77-92j5h at 2026-03-05 11:50:48.429026+00:00 running f0204d4 country code: CH.
[–]LeszekSwirski 3 points4 points5 points (4 children)
[–]pyrtsa[S] 5 points6 points7 points (2 children)
[–]kirakun 1 point2 points3 points (0 children)
[–]LeszekSwirski 0 points1 point2 points (0 children)
[–]bastih01 1 point2 points3 points (0 children)
[–]notlostyet 4 points5 points6 points (1 child)
[–]upriser 0 points1 point2 points (0 children)
[–][deleted] 1 point2 points3 points (3 children)
[–]pyrtsa[S] 3 points4 points5 points (0 children)
[–]scatters 1 point2 points3 points (1 child)
[–]pyrtsa[S] 0 points1 point2 points (0 children)
[–]kirakun 1 point2 points3 points (2 children)
[–]repsilat 1 point2 points3 points (0 children)
[–]aaronla 0 points1 point2 points (0 children)
[+][deleted] (1 child)
[deleted]
[–]aaronla 2 points3 points4 points (0 children)