Skip to content

Instantly share code, notes, and snippets.

@miselin
Last active August 29, 2015 14:01
Show Gist options
  • Save miselin/fbe6b4e428b40ac3c305 to your computer and use it in GitHub Desktop.
Save miselin/fbe6b4e428b40ac3c305 to your computer and use it in GitHub Desktop.
clang++ -std=c++11 -o comma comma.cc
#include <iostream>
#include <list>
#include <vector>
#include <numeric>
#include <type_traits>
#include <typeinfo>
class _dumper {
public:
_dumper() : _dlist() {}
virtual ~_dumper() {}
virtual void basedump(std::ostream &os) const {
if (!_dlist.size()) {
dump(os, false);
} else {
_open(os);
for (auto it : _dlist) {
it->dump(os, true);
}
_close(os);
}
}
virtual void dump(std::ostream &os, bool siblings) const = 0;
protected:
void extend(const _dumper &other) { _dlist.push_back(&other); }
void _open(std::ostream &os) const { os << "( "; }
void _close(std::ostream &os) const { os << ") "; }
private:
std::list<const _dumper *> _dlist;
};
template <typename T> class _basic_tuple : public _dumper {
public:
_basic_tuple() : _dumper(), _list() {}
virtual ~_basic_tuple() {}
_basic_tuple &operator, (T other) {
_list.push_back(other);
return const_cast<_basic_tuple &>(*this);
}
template <typename T2> _basic_tuple &operator, (_basic_tuple<T2> other) {
extend(*this);
extend(other);
return const_cast<_basic_tuple &>(*this);
}
operator size_t() { return _list.size(); }
T operator+() {
auto it = _list.begin();
T r = *(it++);
for (; it != _list.end(); ++it)
r += *it;
return r;
}
T operator*() {
auto it = _list.begin();
T r = *(it++);
for (; it != _list.end(); ++it)
r *= *it;
return r;
}
T operator-() {
auto it = _list.begin();
T r = *(it++);
for (; it != _list.end(); ++it)
r -= *it;
return r;
}
virtual void dump(std::ostream &os = std::cout, bool siblings = false) const {
auto dumper_is_base = std::is_base_of<_dumper, T>();
if (!siblings)
siblings = !dumper_is_base.value;
if (!siblings)
_open(os);
// The right overload must be emitted; it is not possible to simply call
// a different member function based on the result of std::is_base_of,
// as if an object of type T does not have a 'dump' function, the compiler
// errors out in template generation, eg:
// "member reference base type 'const char *' is not a structure or union"
do_dump(os, dumper_is_base);
if (!siblings)
_close(os);
}
private:
std::list<T> _list;
void do_dump(std::ostream &os,
std::true_type /* dummy for overload */) const {
for (auto it : _list) {
it.dump(os, true);
}
}
void do_dump(std::ostream &os,
std::false_type /* dummy for overload */) const {
_open(os);
for (auto it : _list) {
os << it << " ";
}
_close(os);
}
};
class _tuple {
public:
template <typename T> _basic_tuple<T> operator, (T val) {
return _basic_tuple<T>(), val;
}
} _;
std::ostream &operator<<(std::ostream &os, const _dumper &val) {
val.basedump(os);
return os;
}
#define print(x...) \
do { \
_print((_, x)); \
} while (0);
void _print(const _dumper &val) { std::cout << val << std::endl; }
int main(int argc, char *argv[]) {
(_, "hello", "world").dump();
std::cout << std::endl;
size_t count = (_, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
std::cout << count << std::endl;
std::cout << (_, 1, 2) << std::endl;
std::cout << (+(_, (*(_, 3, 2)), 1)) << std::endl;
std::cout << (-(_, 7, 4)) << std::endl;
std::cout << (+(_, std::string("hello"), " ", "world")) << std::endl;
std::cout << "====" << std::endl;
// Mixed types dump as you would expect.
std::cout << (_, (_, 3, 4), (_, 1, 2), (_, "hello world")) << std::endl;
std::cout << (_, (_, 3, 4), (_, 1, 2)) << std::endl;
print("Hello, world!")
print("Hello,", "world!")
}
( hello world )
10
( 1 2 )
7
3
hello world
====
( ( 3 4 ) ( 1 2 ) ( hello world ) )
( ( 3 4 ) ( 1 2 ) )
( Hello, world! )
( Hello, world! )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment