Is there an implementation of a "for each" macro like BOOST_FOREACH that doesn't need Boost?
I've made one.
It should work with C++11 r-value references in GCC and MSVC, but I haven't tested it well so if there's any errors please let me know.
Edit: I added support for strings.
#include <iterator>
#include <utility>
#define foreach(v, r) \
if (fe_detail::any const &fe_r_ = \
fe_detail::make_range(r)) { } else \
if (fe_detail::any const &fe_b_ = \
fe_detail::begin(fe_r_, ((void)0, 1) ? NULL : fe_detail::twrap(r))) { } else \
if (fe_detail::equal( \
fe_b_, \
fe_detail::end(fe_r_, ((void)0, 1) ? NULL : fe_detail::twrap(r)), \
((void)0, 1) ? NULL : fe_detail::twrap(r))) { } else \
for (bool fe_c_ = false; \
!fe_c_ && !fe_detail::equal( \
fe_b_, \
fe_detail::end(fe_r_, ((void)0, 1) ? NULL : fe_detail::twrap(r)), \
((void)0, 1) ? NULL : fe_detail::twrap(r)); \
fe_detail::advance(fe_b_, 1, ((void)0, 1) ? NULL : fe_detail::twrap(r))) \
for (v = (fe_detail::move(*fe_detail::iter(fe_b_, ((void)0, 1) ? NULL : fe_detail::twrap(r)))); \
fe_c_ = !fe_c_; )
namespace fe_detail
{
// Container traits
template<class C, class It> struct CT
{
typedef It It;
static It begin(C &c) { return c.begin(); }
static It end(C &c) { return c.end(); }
};
// Range traits
template<class R> struct RT : public CT<R, typename R::iterator> { };
template<class R> struct RT<R const> : public CT<R const, typename R::const_iterator> { };
template<class R> struct RT<R &> : public RT<R> { };
template<class T, bool B = T::value> struct enable_if;
template<class T> struct enable_if<T, true> { typedef T type; };
template<class T> struct is_char { static bool const value = false; };
template<class T> struct is_char<T const> : public is_char<T> { };
template<class T> struct is_char<T volatile> : public is_char<T> { };
template<> struct is_char<char> { static bool const value = true; };
template<> struct is_char<wchar_t> { static bool const value = true; };
template<class Ch> struct RT<Ch *> : enable_if<is_char<Ch> >
{
typedef Ch *It;
static It begin(It a) { return &a[0]; }
static It end(It a) { return &a[std::char_traits<Ch>::length(a)]; }
};
template<class R, size_t N> struct RT<R[N]>
{
typedef R *It;
static It begin(It a) { return &a[0]; }
static It end(It a) { return &a[N - (((void)0, is_char<R>::value) ? 1 : 0)]; }
};
template<class It> struct RT<std::pair<It, It> >
{
typedef It It;
static It begin(std::pair<It, It> const a) { return a.first; }
static It end(std::pair<It, It> const a) { return a.second; }
};
struct any { operator bool() const { return false; } };
template<class T> struct type_wrap { type_wrap(bool = false) { } };
template<class T> class wrap : public any
{ wrap &operator =(wrap const &); public: mutable T v; wrap(T v) : any(), v(v) { } };
template<class T> class wrap<T const> : public any
{ wrap &operator =(wrap const &); public: T const v; wrap(T const v) : any(), v(v) { } };
template<class T, size_t N> class wrap<T[N]> : public any
{ wrap &operator =(wrap const &); public: T (&v)[N]; wrap(T (&v)[N]) : any(), v(v) { } };
template<class T> class wrap<T const &> : public wrap<T const>
{ wrap &operator =(wrap const &); public: wrap(T const &v) : wrap<T const>(v) { } };
template<class T, size_t N> wrap<T[N]> make_range(T (&r)[N]) { return r; }
template<class T, size_t N> type_wrap<T[N]> twrap(T (&r)[N]) { throw 0; }
template<class It> type_wrap<std::pair<It, It> > twrap(std::pair<It, It> const &p) { throw 0; }
#if defined(_MSC_VER) && _MSC_VER >= 1600 || defined(__RVALUE_REFERENCE) || defined(__GXX_EXPERIMENTAL_CXX0X__)
template<class R> struct RT<R &&> : public RT<R> { };
template<class T> class wrap<T &&> : public wrap<T> { public: wrap(T &&v) : wrap<T>(std::move(v)) { } };
template<class R> wrap<R &&> make_range(R &&r) { return wrap<R &&>(std::forward<R>(r)); }
template<class R> type_wrap<R> twrap(R &&) { throw 0; }
using std::move;
#else
template<class R> wrap<R> make_range(R &r) { return r; }
template<class R> wrap<R const &> make_range(R const &r) { return r; }
template<class R> type_wrap<R> twrap(R &) { throw 0; }
template<class R> type_wrap<R const &> twrap(R const &) { throw 0; }
template<class T> T &move(T &v) { return v; }
template<class T> T const &move(T const &v) { return v; }
#endif
template<class R> wrap<typename RT<R>::It> begin(any const &r, type_wrap<R>)
{ return RT<R>::begin(static_cast<wrap<R> const &>(r).v); }
template<class R> wrap<typename RT<R>::It> end(any const &r, type_wrap<R>)
{ return RT<R>::end (static_cast<wrap<R> const &>(r).v); }
template<class R> bool equal(any const &i, any const &j, type_wrap<R>)
{ return static_cast<wrap<typename RT<R>::It> const &>(i).v == static_cast<wrap<typename RT<R>::It> const &>(j).v; }
template<class R> void advance(any const &i, typename std::iterator_traits<typename RT<R>::It>::difference_type const d, type_wrap<R>)
{ return std::advance(static_cast<wrap<typename RT<R>::It> const &>(i).v, d); }
template<class R> typename RT<R>::It &iter(any const &i, type_wrap<R>)
{ return static_cast<wrap<typename RT<R>::It> const &>(i).v; }
}
You can use it like:
#include <vector>
#include <iostream>
std::vector<int> make_vect()
{
std::vector<int> v;
v.push_back(5);
v.push_back(8);
v.push_back(10);
return v;
}
int main()
{
foreach (int c, make_vect())
{
std::cout << c << std::endl;
}
}
Related
I'm trying to create a struct of arrays:
auto x = MakeMegaContainer<StructA, StructB, StructC>();
Which I want to, at compile time, produce a structure like:
struct MegaContainer {
std::tuple< Container<StructA>, Container<StructB>, Container<StructC> > Data;
};
The creation method is non-negotiable, and I think tuples are the best way to go, as later I could access one container's struct elements with std::get<StructA>(x)[index], if my container allows [].
I tried doing something like:
template<typename... LilStructs>
class StructStorage {
public:
template<typename OneStruct>
OneStruct& GetStruct(const uint64_t& id) {
return std::get<OneStruct>(m_Storage).Get(id); // Get is defined for MyContainer
}
template<typename OneStruct>
bool ContainsStruct(const uint64_t& id) {
return std::get<OneStruct>(m_Storage).Contains(id); // Contains is defined for MyContainer
}
private:
std::tuple<MyContainer<LilStructs>...> m_Storage;
};
But I don't think this works. I'm not sure how to take the variadic arguments and "wrap" them with a container
What should I do instead?
Follow up question: The MyContainer also takes additional arguments that customise it, like a max size. Is there a nice way of passing that, something like template<typename... LilStructs, uint64_t MAX_SIZE=4096>?
Here's a stripped down version of the container for a minimal reproducible example:
template<typename T_elem, typename T_int = uint64_t, T_int MAX_SIZE = 4096>
class MyContainer{
public:
MyContainer() = default;
~MyContainer() = default;
bool Contains(const T_int& id) const;
T_elem& operator[](const T_int& id);
T_elem& Get(const T_int& id);
private:
std::map<T_int, T_elem> m_Map;
T_int m_Size = 0;
};
template<typename T_elem, typename T_int, T_int MAX_SIZE>
bool MyContainer<T_elem, T_int, MAX_SIZE>::Contains(
const T_int& id
) const {
return m_Map[id] < m_Size;
}
template<typename T_elem, typename T_int, T_int MAX_SIZE>
T_elem& MyContainer<T_elem, T_int, MAX_SIZE>::operator[](const T_int& id) {
return m_Map[id];
}
template<typename T_elem, typename T_int, T_int MAX_SIZE>
T_elem& MyContainer<T_elem, T_int, MAX_SIZE>::Get(const T_int& id) {
return operator[](id);
}
When I try to compile:
void Test() {
struct SA { int x; };
struct SB { float x; };
struct SC { char x; };
auto& tests = StructStorage <SA, SB, SC>();
bool x = !tests.ContainsStruct<SA>(5);
}
I get the error:
c:\...\test.h(18): error C2039: 'Contains': is not a member of 'Trial::SA'
As I said, I know the error is in the std::tuple<MyContainer<LilStructs>...> m_Storage; line, and the error is indpendent of the implementation of MyContainer (provided that Contains and Get are implemented), but I do not know what to replace it with, or how to achieve the functionality I'm looking for (which was already described).
Look at this part:
template <typename OneStruct>
OneStruct& GetStruct(const uint64_t& id) {
return std::get<OneStruct>(m_Storage).Get(id); // Get is defined for MyContainer
}
template <typename OneStruct>
bool ContainsStruct(const uint64_t& id) {
return std::get<OneStruct>(m_Storage).Contains(id); // Contains is defined for MyContainer
}
The m_Storage tuple is a tuple of MyContainer<LilStructs>...s and not LilStructs...s so what you actually want to do is this:
template <typename OneStruct>
OneStruct& GetStruct(const uint64_t& id) {
return std::get<MyContainer<OneStruct>>(m_Storage).Get(id); // Get is defined for MyContainer
// ^^^^^^^^^^^^^^^^^^^^^^
}
template <typename OneStruct>
bool ContainsStruct(const uint64_t& id) {
return std::get<MyContainer<OneStruct>>(m_Storage).Contains(id); // Contains is defined for MyContainer
// ^^^^^^^^^^^^^^^^^^^^^^
}
Also, your Contains() function is wrong. Use this:
template <typename T_elem, typename T_int, T_int MAX_SIZE>
bool MyContainer<T_elem, T_int, MAX_SIZE>::Contains(const T_int& id) const {
return m_Map.find(id) != m_Map.end();
}
Full working code:
#include <cstdint>
#include <cassert>
#include <tuple>
#include <map>
template <typename T_elem, typename T_int = uint64_t, T_int MAX_SIZE = 4096>
class MyContainer{
public:
MyContainer() = default;
~MyContainer() = default;
bool Contains(const T_int& id) const;
T_elem& operator[](const T_int& id);
T_elem& Get(const T_int& id);
private:
std::map<T_int, T_elem> m_Map;
T_int m_Size = 0;
};
template <typename T_elem, typename T_int, T_int MAX_SIZE>
bool MyContainer<T_elem, T_int, MAX_SIZE>::Contains(const T_int& id) const {
return m_Map.find(id) != m_Map.end();
}
template <typename T_elem, typename T_int, T_int MAX_SIZE>
T_elem& MyContainer<T_elem, T_int, MAX_SIZE>::operator[](const T_int& id) {
return m_Map[id];
}
template <typename T_elem, typename T_int, T_int MAX_SIZE>
T_elem& MyContainer<T_elem, T_int, MAX_SIZE>::Get(const T_int& id) {
return operator[](id);
}
template <typename ...LilStructs>
class StructStorage {
public:
template <typename OneStruct>
OneStruct& GetStruct(const uint64_t& id) {
return std::get<MyContainer<OneStruct>>(m_Storage).Get(id);
}
template <typename OneStruct>
bool ContainsStruct(const uint64_t& id) {
return std::get<MyContainer<OneStruct>>(m_Storage).Contains(id);
}
private:
std::tuple<MyContainer<LilStructs>...> m_Storage;
};
int main() {
struct SA { int x; };
struct SB { float x; };
struct SC { char x; };
auto tests = StructStorage<SA, SB, SC>();
assert(!tests.ContainsStruct<SA>(5));
}
Demo
i am currently working on a c++ project and now i am stuck already for a while. It's about delayed evaluation with expression templates and (for me at least) a strange bad_alloc.
If you try the code below, you'll notice runtime error bad_alloc due to the very last addition b+c. So thats the point where the delayed evaluation is done. Furthermore the code below compiles and runs fine if you remove the references of the members of "Expression" (left,right). But i need references there, due to performance, etc. . However i also dont see, why i cant use references there.
I've already spent a lot of time with it. Please let me know if somebody can help me.
Best Regards.
#include <iostream>
#include <vector>
template<typename value_t, typename left_t, typename right_t, typename op_t>
class Expression
{
public:
typedef value_t value_type;
explicit Expression(const left_t &left,
const right_t &right,
const op_t &op) :
left(left),
right(right),
op(op)
{
}
value_t operator [](const size_t &i) const
{
return op(left[i],right[i]);
}
size_t size() const { return left.size();}
private:
const left_t &left;
const right_t &right;
//const left_t left;
//const right_t right;
const op_t &op;
};
template<class left_t,
class right_t,
class value_t = typename left_t::value_type,
class op_t = std::plus<value_t>>
const Expression<value_t, left_t, right_t, op_t> operator +(const left_t &left,
const right_t &right)
{
return Expression<value_t,left_t,right_t,op_t>(left, right, op_t());
}
template<typename value_t, typename data_t = std::vector<value_t>>
class Vector : public data_t
{
public:
typedef value_t value_type;
using data_t::size;
Vector(const std::initializer_list<value_t> &list) :
data_t(list)
{
}
Vector(const size_t &n) :
data_t(n)
{
}
Vector(const Vector &v) :
data_t(v)
{
}
template<typename left_t, typename right_t, typename op_t>
Vector(const Expression<value_t,left_t,right_t,op_t> &v) :
data_t(v.size())
{
operator =(v);
}
template<typename vec_t>
Vector(const vec_t &v) :
data_t(v.size())
{
operator =(v);
}
template<typename vec_t>
Vector &operator =(const vec_t &v)
{
for(size_t i = 0; i < data_t::size(); ++i)
data_t::operator [](i) = v[i];
return (*this);
}
friend std::ostream &operator <<(std::ostream &os, const Vector &v)
{
if(v.size())
os << v[0];
for(size_t i = 1; i < v.size(); ++i)
os << " " << v[i];
return os;
}
};
int main()
{
Vector<double> a{0,1,2};
auto b = a+a+a;
auto c = a;
std::cout << a+a+a+a << std::endl;
std::cout << b+c << std::endl; // gives bad_alloc
return 0;
}
"But i need references there, due to performance, etc."
Prove it.
In expression templates, all¹ the information should be compile-time.
You can see my example here for a simple expression template:
// we have lazy placeholder types:
template <int N> struct placeholder {};
placeholder<1> _1;
placeholder<2> _2;
placeholder<3> _3;
// note that every type here is stateless, and acts just like a more
// complicated placeholder.
// We can have expressions, like binary addition:
template <typename L, typename R> struct addition { };
template <typename L, typename R> struct multiplication { };
// here is the "factory" for our expression template:
template <typename L, typename R> addition<L,R> operator+(L const&, R const&) { return {}; }
template <typename L, typename R> multiplication<L,R> operator*(L const&, R const&) { return {}; }
///////////////////////////////////////////////
// To evaluate/interpret the expressions, we have to define "evaluation" for each type of placeholder:
template <typename Ctx, int N>
auto eval(Ctx& ctx, placeholder<N>) { return ctx.arg(N); }
template <typename Ctx, typename L, typename R>
auto eval(Ctx& ctx, addition<L, R>) { return eval(ctx, L{}) + eval(ctx, R{}); }
template <typename Ctx, typename L, typename R>
auto eval(Ctx& ctx, multiplication<L, R>) { return eval(ctx, L{}) * eval(ctx, R{}); }
///////////////////////////////////////////////
// A simple real-life context would contain the arguments:
#include <vector>
struct Context {
std::vector<double> _args;
// define the operation to get an argument from this context:
double arg(int i) const { return _args.at(i-1); }
};
#include <iostream>
int main() {
auto foo = _1 + _2 + _3;
Context ctx { { 3, 10, -4 } };
std::cout << "foo: " << eval(ctx, foo) << "\n";
std::cout << "_1 + _2 * _3: " << eval(ctx, _1 + _2 * _3) << "\n";
}
So what you need is a literal type that holds a reference to the associated value, and defer all other evaluation to evaluation time.
I might prefer to add the size() operation as a free function, so that you don't have to encumber all the expression types with it (Separation Of Concerns).
¹ nearly, nl. except when encoding literals
Proof Of Concept
Using the strategy outlined:
Live On Coliru
#include <iostream>
#include <tuple>
namespace ETL {
template <typename T>
struct Literal {
T value;
T get() const { return value; }
};
/*
*template <typename T>
* static inline std::ostream& operator<<(std::ostream& os, ETL::Literal<T> const& lit) {
* return os << __PRETTY_FUNCTION__ << "\n actual: lit.value = " << lit.value;
* }
*/
template <class L, class R, class Op>
struct BinaryExpr : std::tuple<L, R, Op> { // tuple optimizes for empty element types
BinaryExpr(L l, R r, Op op)
: std::tuple<L, R, Op> { l, r, op }
{}
L const& get_lhs() const { return std::get<0>(*this); }
R const& get_rhs() const { return std::get<1>(*this); }
Op const& get_op() const { return std::get<2>(*this); }
};
template <class L, class R, class Op> auto cured(BinaryExpr<L,R,Op> _) { return _; }
template <class T> auto cured(Literal<T> l) { return std::move(l); }
template <class T> Literal<T> cured(T&& v) { return {std::forward<T>(v)}; }
template <class Op, class L, class R>
BinaryExpr<L, R, Op> make_binexpr(L&& l, R&& r) { return { std::forward<L>(l), std::forward<R>(r), Op{} }; }
template <class L, class R> auto operator +(L&& l, R&& r)
{ return make_binexpr<std::plus<>>(cured(std::forward<L>(l)), cured(std::forward<R>(r))); }
template <class L, class R> auto operator -(L&& l, R&& r)
{ return make_binexpr<std::minus<>>(cured(std::forward<L>(l)), cured(std::forward<R>(r))); }
template <class L, class R> auto operator *(L&& l, R&& r)
{ return make_binexpr<std::multiplies<>>(cured(std::forward<L>(l)), cured(std::forward<R>(r))); }
template <class L, class R> auto operator /(L&& l, R&& r)
{ return make_binexpr<std::divides<>>(cured(std::forward<L>(l)), cured(std::forward<R>(r))); }
template <class L, class R> auto operator %(L&& l, R&& r)
{ return make_binexpr<std::modulus<>>(cured(std::forward<L>(l)), std::forward<R>(r)); }
template <typename T> auto val(T const& v)
{ return cured(v); }
namespace impl {
template <class T>
static constexpr auto is_indexable(T const&) -> decltype(std::declval<T const&>()[0], std::true_type{}) { return {}; }
static constexpr auto is_indexable(...) -> decltype(std::false_type{}) { return {}; }
struct {
template <class T> size_t operator()(T const& v) const { return (*this)(v, is_indexable(v)); }
template <class T> size_t operator()(T const& v, std::true_type) const { return v.size(); }
template <class T> size_t operator()(T const&, std::false_type) const { return 0; }
template <class T> size_t operator()(Literal<T> const& l) const { return (*this)(l.value); }
template <class L, class R, class Op>
size_t operator()(BinaryExpr<L,R,Op> const& be) const { return (*this)(be.get_lhs()); }
} size;
struct {
template <class T>
auto operator()(size_t i, T const& v) const { return (*this)(i, v, is_indexable(v)); }
template <class T>
auto operator()(size_t i, T const& v, std::true_type) const { return v[i]; }
template <class T>
auto operator()(size_t, T const& v, std::false_type) const { return v; }
template <class T> auto operator()(size_t i, Literal<T> const& l) const { return (*this)(i, l.value); }
template <class L, class R, class Op>
auto operator()(size_t i, BinaryExpr<L,R,Op> const& be) const {
return be.get_op()((*this)(i, be.get_lhs()), (*this)(i, be.get_rhs()));
}
} eval_at;
}
template <typename T> size_t size(T const& v) { return impl::size(v); }
template <typename T> auto eval_at(size_t i, T const& v) { return impl::eval_at(i, v); }
}
#include <vector>
template <class value_t>
struct Vector : std::vector<value_t> {
using data_t = std::vector<value_t>;
typedef value_t value_type;
using data_t::data_t;
template <typename Expr>
Vector(Expr const& expr) { *this = expr; }
template <typename Expr>
Vector& operator=(Expr const& expr) {
this->resize(size(expr));
for (size_t i = 0; i < this->size(); ++i)
this->at(i) = eval_at(i, expr);
return *this;
}
friend std::ostream &operator<<(std::ostream &os, const Vector &v) {
for (auto& el : v) os << " " << el;
return os;
}
};
int main() {
Vector<double> a { 1, 2, 3 };
using ETL::operator+;
using ETL::operator*;
//std::cout << typeid(a + a * 4 / 2).name() << "\n";
#define DD(x) std::cout << typeid(x).name() << " size: " << ETL::size(x) << " result:" << (x) << "\n"
DD(a * -100.0);
auto b = a + a + a;
auto c = a;
std::cout << size(b) << "\n";
std::cout << (a + a + a + a) << "\n";
std::cout << a * 4.0 << "\n";
std::cout << b + c << "\n";
std::cout << (a + a + a + a) - 4 * a << "\n";
}
Prints
ETL::BinaryExpr<ETL::Literal<Vector<double>&>, ETL::Literal<double>, std::multiplies<void> > size: 3 result: -100 -200 -300
3
4 8 12
4 8 12
4 8 12
0 0 0
Here is the code:
template <typename L, typename R> bool eq (const L& lhs, const R& rhs) { return lhs == rhs; }
template<int N> bool eq(char* lhs, const char(&rhs)[N]) { return String(lhs).compare(rhs) == 0; }
template<int N> bool eq(const char(&lhs)[N], char* rhs) { return String(lhs).compare(rhs) == 0; }
inline bool eq(char* lhs, char* rhs) { return String(lhs).compare(rhs) == 0; }
inline bool eq(const char* lhs, const char* rhs) { return String(lhs).compare(rhs) == 0; }
inline bool eq(char* lhs, const char* rhs) { return String(lhs).compare(rhs) == 0; }
inline bool eq(const char* lhs, char* rhs) { return String(lhs).compare(rhs) == 0; }
I have to do this for neq/lt/gt/lte/gte and not just for equality. Maybe I've already missed something.
Is there a way to not list all the possible combinations of C string types?
Also C++98.
EDIT: >> here << is an online demo with the problem
Decay an array type to pointer:
template<class T>
struct decay_array { typedef T type; };
template<class T, size_t N>
struct decay_array<T[N]> { typedef T* type; };
template<class T>
struct decay_array<T[]> { typedef T* type; };
Check that a type is not a pointer to (possibly const) char:
template<class T>
struct not_char_pointer { enum { value = true }; };
template<>
struct not_char_pointer<char*> { enum { value = false }; };
template<>
struct not_char_pointer<const char*> { enum { value = false }; };
Now check that a type is not a pointer to or array of (possibly const) char:
template<class T>
struct can_use_op : not_char_pointer<typename decay_array<T>::type> {};
Reimplement std::enable_if:
template<bool, class = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
and use it to constrain your template:
template <typename L, typename R>
typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type
eq (const L& lhs, const R& rhs) { return lhs == rhs; }
Then just one overload is enough:
inline bool eq(const char* lhs, const char* rhs) { return String(lhs).compare(rhs) == 0; }
namespace details{
template<template<class...>class Z,class,class...Ts>
struct can_apply:std::false_type{};
template<template<class...>class Z,class...Ts>
struct can_apply<Z,std::void_t<Z<Ts...>>,Ts...>:std::true_type{};
}
template<template<class...>class Z,class...Ts>
using can_apply=details::can_apply<Z,void,Ts...>;
This tests if a template can be applied some types.
namespace strcmp{
bool eq(const char*lhs, const char*rhs){/* body */}
}
template<class L, class R>
using str_eq_r=decltype(strcmp::eq(std::declval<L>(),std::declval<R>()));
template<class L, class R>
using can_str_eq=can_apply<str_eq_r,L,R>;
can_str_eq is truthy iff we can call stdcmp::eq on it.
namespace details {
bool eq(const char* lhs, const char* rhs, std::true_type){
return strcmp::eq(lhs,rhs);
}
template<class L,class R>
bool eq(L const& l, R const&r,std::false_type){
return l==r;
}
}
template<class L,class R>
bool eq(L const& l, R const&r){
return details::eq(l,r,can_str_eq<L const&,R const&>{});;
}
We could also use a static_if trick to do it inline, if you like:
template<class L,class R>
bool eq(L const& l, R const&r){
return static_if<can_str_eq>( l, r )(
strcmp::eq,
[](auto&& l, auto&& r){return l==r;}
);
}
After writing a static_if:
template<class...Ts>
auto functor(Ts...ts){
return [=](auto&& f){
return f(ts...);
};
}
namespace details{
template<class Functor>
auto switcher(std::true_type, Functor functor){
return [=](auto&& t, auto&&){
return functor(t);
};
}
template<class Functor>
auto switcher(std::false_type, Functor functor){
return [=](auto&&, auto&& f){
return functor(f);
};
}
}
template<template<class...>class test, class...Ts>
auto static_if(Ts...ts){
return details::switcher(
test<Ts...>{},
functor(ts...)
);
}
now, what are the odds that works? (Written on phone, not compiled yet) Also not optimal: lots of perfect forwarding, some of which requires de-lamdaing, required.
The Problem
This question relates to several questions about function pointers here (I will not list them), but most importantly it concerns the code posted here. The post claims the code should be standard compliant and it compiles on Apple Clang just fine.
I have not managed to compile it in VS2015, i.e. MSVC++14.
What could be the source of this error and why not with Clang?
First Error
First error repeats multiple times:
...\Delegate.hpp(329): error C2514: 'Delegate<R(A...)>::is_member_pair<<unnamed-symbol>>':
class has no constructors
And the same for is_member_pair_const. It relates to the following part of the code:
template <typename T>
static typename ::std::enable_if<
!(is_member_pair<T>{} ||
is_const_member_pair<T>{}),
R>::type
functor_stub(void* const object_ptr, A&&... args)
{
return (*static_cast<T*>(object_ptr))(::std::forward<A>(args)...);
}
Second Error
Multiple errors appear, but the first is usually most important:
...\Delegate.hpp(340): error C2059: syntax error: '<end Parse>'
...\Delegate.hpp(349): note: see reference to class template instantiation 'Delegate<R(A...)>' being compiled
Then follow a few syntax errors, unrecognizable template declaration/definition etc. The code in question:
template <typename T>
static typename ::std::enable_if<
is_member_pair<T>{} ||
is_const_member_pair<T>{},
R
>::type
functor_stub(void* const object_ptr, A&&... args)
{
return (static_cast<T*>(object_ptr)->first->*
static_cast<T*>(object_ptr)->second)(::std::forward<A>(args)...);
}
For Completeness: The entire Delegate.hpp:
Code Source and Base Article
#pragma once
#ifndef DELEGATE_HPP
#define DELEGATE_HPP
#include <cassert>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>
template <typename T> class Delegate;
template<class R, class ...A>
class Delegate<R (A...)>
{
using stub_ptr_type = R (*)(void*, A&&...);
Delegate(void* const o, stub_ptr_type const m) noexcept :
object_ptr_(o),
stub_ptr_(m)
{
}
public:
Delegate() = default;
Delegate(Delegate const&) = default;
Delegate(Delegate&&) = default;
Delegate(::std::nullptr_t const) noexcept : Delegate() { }
template <class C, typename =
typename ::std::enable_if< ::std::is_class<C>{}>::type>
explicit Delegate(C const* const o) noexcept :
object_ptr_(const_cast<C*>(o))
{
}
template <class C, typename =
typename ::std::enable_if< ::std::is_class<C>{}>::type>
explicit Delegate(C const& o) noexcept :
object_ptr_(const_cast<C*>(&o))
{
}
template <class C>
Delegate(C* const object_ptr, R (C::* const method_ptr)(A...))
{
*this = from(object_ptr, method_ptr);
}
template <class C>
Delegate(C* const object_ptr, R (C::* const method_ptr)(A...) const)
{
*this = from(object_ptr, method_ptr);
}
template <class C>
Delegate(C& object, R (C::* const method_ptr)(A...))
{
*this = from(object, method_ptr);
}
template <class C>
Delegate(C const& object, R (C::* const method_ptr)(A...) const)
{
*this = from(object, method_ptr);
}
template <
typename T,
typename = typename ::std::enable_if<
!::std::is_same<Delegate, typename ::std::decay<T>::type>{}
>::type
>
Delegate(T&& f) :
store_(operator new(sizeof(typename ::std::decay<T>::type)),
functor_deleter<typename ::std::decay<T>::type>),
store_size_(sizeof(typename ::std::decay<T>::type))
{
using functor_type = typename ::std::decay<T>::type;
new (store_.get()) functor_type(::std::forward<T>(f));
object_ptr_ = store_.get();
stub_ptr_ = functor_stub<functor_type>;
deleter_ = deleter_stub<functor_type>;
}
Delegate& operator=(Delegate const&) = default;
Delegate& operator=(Delegate&&) = default;
template <class C>
Delegate& operator=(R (C::* const rhs)(A...))
{
return *this = from(static_cast<C*>(object_ptr_), rhs);
}
template <class C>
Delegate& operator=(R (C::* const rhs)(A...) const)
{
return *this = from(static_cast<C const*>(object_ptr_), rhs);
}
template <
typename T,
typename = typename ::std::enable_if<
!::std::is_same<Delegate, typename ::std::decay<T>::type>{}
>::type
>
Delegate& operator=(T&& f)
{
using functor_type = typename ::std::decay<T>::type;
if ((sizeof(functor_type) > store_size_) || !store_.unique())
{
store_.reset(operator new(sizeof(functor_type)),
functor_deleter<functor_type>);
store_size_ = sizeof(functor_type);
}
else
{
deleter_(store_.get());
}
new (store_.get()) functor_type(::std::forward<T>(f));
object_ptr_ = store_.get();
stub_ptr_ = functor_stub<functor_type>;
deleter_ = deleter_stub<functor_type>;
return *this;
}
template <R (* const function_ptr)(A...)>
static Delegate from() noexcept
{
return { nullptr, function_stub<function_ptr> };
}
template <class C, R (C::* const method_ptr)(A...)>
static Delegate from(C* const object_ptr) noexcept
{
return { object_ptr, method_stub<C, method_ptr> };
}
template <class C, R (C::* const method_ptr)(A...) const>
static Delegate from(C const* const object_ptr) noexcept
{
return { const_cast<C*>(object_ptr), const_method_stub<C, method_ptr> };
}
template <class C, R (C::* const method_ptr)(A...)>
static Delegate from(C& object) noexcept
{
return { &object, method_stub<C, method_ptr> };
}
template <class C, R (C::* const method_ptr)(A...) const>
static Delegate from(C const& object) noexcept
{
return { const_cast<C*>(&object), const_method_stub<C, method_ptr> };
}
template <typename T>
static Delegate from(T&& f)
{
return ::std::forward<T>(f);
}
static Delegate from(R (* const function_ptr)(A...))
{
return function_ptr;
}
template <class C>
using member_pair =
::std::pair<C* const, R (C::* const)(A...)>;
template <class C>
using const_member_pair =
::std::pair<C const* const, R (C::* const)(A...) const>;
template <class C>
static Delegate from(C* const object_ptr,
R (C::* const method_ptr)(A...))
{
return member_pair<C>(object_ptr, method_ptr);
}
template <class C>
static Delegate from(C const* const object_ptr,
R (C::* const method_ptr)(A...) const)
{
return const_member_pair<C>(object_ptr, method_ptr);
}
template <class C>
static Delegate from(C& object, R (C::* const method_ptr)(A...))
{
return member_pair<C>(&object, method_ptr);
}
template <class C>
static Delegate from(C const& object,
R (C::* const method_ptr)(A...) const)
{
return const_member_pair<C>(&object, method_ptr);
}
void reset() { stub_ptr_ = nullptr; store_.reset(); }
void reset_stub() noexcept { stub_ptr_ = nullptr; }
void swap(Delegate& other) noexcept { ::std::swap(*this, other); }
bool operator==(Delegate const& rhs) const noexcept
{
return (object_ptr_ == rhs.object_ptr_) && (stub_ptr_ == rhs.stub_ptr_);
}
bool operator!=(Delegate const& rhs) const noexcept
{
return !operator==(rhs);
}
bool operator<(Delegate const& rhs) const noexcept
{
return (object_ptr_ < rhs.object_ptr_) ||
((object_ptr_ == rhs.object_ptr_) && (stub_ptr_ < rhs.stub_ptr_));
}
bool operator==(::std::nullptr_t const) const noexcept
{
return !stub_ptr_;
}
bool operator!=(::std::nullptr_t const) const noexcept
{
return stub_ptr_;
}
explicit operator bool() const noexcept { return stub_ptr_; }
R operator()(A... args) const
{
// assert(stub_ptr);
return stub_ptr_(object_ptr_, ::std::forward<A>(args)...);
}
private:
friend struct ::std::hash<Delegate>;
using deleter_type = void (*)(void*);
void* object_ptr_;
stub_ptr_type stub_ptr_{};
deleter_type deleter_;
::std::shared_ptr<void> store_;
::std::size_t store_size_;
template <class T>
static void functor_deleter(void* const p)
{
static_cast<T*>(p)->~T();
operator delete(p);
}
template <class T>
static void deleter_stub(void* const p)
{
static_cast<T*>(p)->~T();
}
template <R (*function_ptr)(A...)>
static R function_stub(void* const, A&&... args)
{
return function_ptr(::std::forward<A>(args)...);
}
template <class C, R (C::*method_ptr)(A...)>
static R method_stub(void* const object_ptr, A&&... args)
{
return (static_cast<C*>(object_ptr)->*method_ptr)(
::std::forward<A>(args)...);
}
template <class C, R (C::*method_ptr)(A...) const>
static R const_method_stub(void* const object_ptr, A&&... args)
{
return (static_cast<C const*>(object_ptr)->*method_ptr)(
::std::forward<A>(args)...);
}
template <typename>
struct is_member_pair : std::false_type { };
template <class C>
struct is_member_pair< ::std::pair<C* const,
R (C::* const)(A...)> > : std::true_type
{
};
template <typename>
struct is_const_member_pair : std::false_type { };
template <class C>
struct is_const_member_pair< ::std::pair<C const* const,
R (C::* const)(A...) const> > : std::true_type
{
};
template <typename T>
static typename ::std::enable_if<
!(is_member_pair<T>{} ||
is_const_member_pair<T>{}),
R
>::type
functor_stub(void* const object_ptr, A&&... args)
{
return (*static_cast<T*>(object_ptr))(::std::forward<A>(args)...);
}
template <typename T>
static typename ::std::enable_if<
is_member_pair<T>{} ||
is_const_member_pair<T>{},
R
>::type
functor_stub(void* const object_ptr, A&&... args)
{
return (static_cast<T*>(object_ptr)->first->*
static_cast<T*>(object_ptr)->second)(::std::forward<A>(args)...);
}
};
namespace std
{
template <typename R, typename ...A>
struct hash<::Delegate<R (A...)> >
{
size_t operator()(::Delegate<R (A...)> const& d) const noexcept
{
auto const seed(hash<void*>()(d.object_ptr_));
return hash<typename ::Delegate<R (A...)>::stub_ptr_type>()(
d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
};
}
#endif // DELEGATE_HPP
As Igor commented, the following solves the problem: replace is_member_pair<T>{} with is_member_pair<T>::value everywhere and do the same for is_const_member_pair.
I'm trying to write a C++ version of Python's itertools.tee for Boost::Range (as seen here). Here is my first attempt:
template<typename R>
class tee_iterator : std::iterator<std::forward_iterator_tag, typename boost::range_value<R>::type>
{
public:
typedef typename boost::range_value<R>::type T;
typedef std::list<T> tee_queue;
typedef std::vector<tee_queue> tee_queue_collection;
tee_iterator(const R& r, tee_queue* q, tee_queue_collection* qs) :
it_(r.begin()), queue_(q), queues_(qs) {}
tee_iterator(const R& r) : it_(r.end()), queue_(NULL), queues_(NULL) {}
T& operator*() const { return current_; }
tee_iterator& operator++()
{
if (queue_->empty()) {
++it_;
for (auto q : queues_) {
q->push_back(*it_);
}
}
current_ = queue_->front();
queue_->pop_front();
return *this;
}
bool operator==(tee_iterator const& o) const { return it_ == o.it_; }
bool operator!=(tee_iterator const& o) const { return !(*this == o); }
private:
typedef typename boost::range_iterator<const R>::type const_iterator;
const_iterator it_;
tee_queue* queue_;
tee_queue_collection* queues_;
T current_;
};
template<typename R>
using tee_range = boost::iterator_range<tee_iterator<R> >;
template<typename R>
std::list<tee_range<R> > tee(const R& r, int n)
{
typedef typename boost::range_value<R>::type T;
typedef std::list<T> tee_queue;
typedef std::vector<tee_queue> tee_queue_collection;
tee_queue_collection queues(n);
std::list<tee_range<R> > ranges;
for (int i = 0; i < n; ++i) {
tee_range<R> t = { tee_iterator<R>(r, &queues[i], &queues), tee_iterator<R>(r) };
ranges.push_back(t);
}
return ranges;
}
but as soon as I try to use it:
int main(int argc, char* argv[])
{
std::list<int> l;
for (int i = 0; i < 10; ++i) {
l.push_back(i);
}
auto t = tee(l, 3);
}
it blows in my face, complaining about a missing value_type in boost::detail::iterator_traits<tee_iterator<std::list<int, std::allocator<int> > > > (and others). What am I missing? Isn't tee_iterator being a child of std::iterator enough?
You forgot to add public:
class tee_iterator : public std::iterator...