I'm trying to design a function that will take any number of function pointers that return different types. How can I make h compile?
#include <string>
template<typename T, typename U>
void g(T(*f1)(void) -> T, U(*f2)(void) -> U) {
}
template<typename ...T>
void h(T(*f)(void) -> T...) {
}
int main(int argc, char** argv) {
g(
+[]() -> int { return 123; },
+[]() -> std::string { return "321"; }
);
h(
+[]() -> int { return 123; },
+[]() -> std::string { return "321"; }
);
}
It is entirely possible I'm being really stupid here. Is it the parameter expansion Im doing wrong, or something else?
You don't need trailing return types in g and f declarations, and ... is in a wrong place.
Fixed version:
#include <string>
template<typename T, typename U>
void g(T(*f1)(void), U(*f2)(void)) {
}
template<typename ...T>
void h(T(*...f)(void)) {
}
int main(int argc, char** argv) {
g(
+[]() -> int { return 123; },
+[]() -> std::string { return "321"; }
);
h(
+[]() -> int { return 123; },
+[]() -> std::string { return "321"; }
);
}
Related
I'm looking into a solution of building containers which track stored size of their elements in addition to basic functions.
So far I didn't saw a solution which doesn't create a huge amount of boilerplate code of each invalidating member of container. This also assumes that stored elements cannot change size after being stored.
Unless standard containers have some feature that allows to inject such behaviour. The following example should be working one, albeit abridged for brevity. The declarations used are:
typedef uint8_t Byte;
typedef Byte PacketId;
template <class T>
struct CollectionTraits {
typedef T collection_type;
typedef typename collection_type::value_type value_type;
typedef typename collection_type::size_type size_type;
typedef typename collection_type::iterator iterator;
typedef typename collection_type::reference reference;
typedef typename collection_type::const_iterator const_iterator;
const_iterator begin() const { return _collection.begin(); }
const_iterator end() const { return _collection.end(); }
iterator begin() { return _collection.begin(); }
iterator end() { return _collection.end(); }
size_type size() const { return _collection.size(); }
protected:
T _collection;
};
struct Packet : CollectionTraits<std::vector<Byte>>
{
PacketId id;
};
The container itself:
struct PacketList : CollectionTraits<std::deque<Packet>>
{
public:
typedef Packet::size_type data_size;
void clear() { _collection.clear(); _total_size = 0; }
data_size total_size() const { return _total_size; }
void push_back(const Packet& v) {
_collection.push_back(v);
_add(v);
}
void push_back(const Packet&& v) {
_collection.push_back(std::move(v));
_add(v);
}
void push_front(const Packet& v) {
_collection.push_front(v);
_add(v);
}
void push_front(const Packet&& v) {
_collection.push_front(std::move(v));
_add(v);
}
void pop_back() {
_remove(_collection.back());
_collection.pop_back();
}
void erase(const_iterator first, const_iterator last) {
for(auto it = first; it != last; ++it) _remove(*it);
_collection.erase(first, last);
}
PacketList() : _total_size(0) {}
PacketList(const PacketList& other) : _total_size(other._total_size) {}
private:
void _add(const Packet& v) { _total_size += v.size(); }
void _remove(const Packet& v) { _total_size -= v.size(); }
data_size _total_size;
};
The interface in result should similar to a standard container. Is there a way to avoid this amount of repeated code? Is there some standard solution for this problem?
I want to create a hastable to member templated functor, I explain.
Here is my exemple which does'nt work:
#include <iostream>
#include <unordered_map>
using namespace std;
class MyFirstClass
{
int i_;
public:
MyFirstClass(): i_(0) {}
void setI(int i) { i_ = i; }
int getI() { return i_; }
};
class MySecondClass
{
bool b_;
public:
MySecondClass(): b_(0) {}
void setB(bool b) { b_ = b; }
bool getB() { return b_; }
};
template<class X, void (X::*p)()>
class MyFunctor
{
X& _x;
public:
MyFunctor(X& x) : _x( x ) {}
void operator()() const { (_x.*p)(); }
};
int main(int argc, char *argv[])
{
unordered_map<string,MyFunctor> myHashTable;
MyFirstClass first;
MyFirstClass second;
myHashTable["int"] = first::setI;
myHashTable["bool"] = second::setB;
//
string key = "bool";
int value = 1;
myHashTable[key](value);
return 0;
}
I have multiple class with their own setter . I would like to be able thanks to the has table and a command {string,int} change the value of the corresponding class.
The previous code is not working for the moment and I am stuck.
There are a few problems with your code, as it stands.
Firstly, from your example unordered_map<string,MyFunctor> doesn't name a type, because MyFunctor doesn't name a type. You could create a non-template base class with a virtual operator(), and then have MyFunctor inherit from it.
Second, you aren't using compatible method pointers, MyFirstClass::setI and MySecondClass::setB both take a parameter.
Third, related to the first, you have to specify the template parameters when constructing an object from a class template. (until c++17's class template deduction guides). You also have ungrammatical syntax that I assume is trying to specify the object argument to the MyFunctor constructor alongside the method-pointer template argument.
You would have something like
class MyFunctorBase {
virtual void operator()(void * i) const = 0;
}
template<class T, class X, void (X::*p)(T)>
class MyFunctor : public MyFunctorBase
{
X& _x;
public:
MyFunctor(X& x) : _x( x ) {}
void operator()(void * i) const override { (_x.*p)(*static_cast<T*>(i)); }
};
int main(int argc, char *argv[])
{
unordered_map<string,shared_ptr<MyFunctorBase>> myHashTable;
MyFirstClass first;
MyFirstClass second;
myHashTable["int"] = make_shared<MyFunctor<int, MyFirstClass, &MyFirstClass::setI>>(first);
myHashTable["bool"] = make_shared<MyFunctor<bool, MySecondClass, &MySecondClass::setB>>(second);
//
string key = "bool";
bool value = true;
(*myHashTable[key])(static_cast<void *>(&value));
return 0;
}
Or, much more easily, use the existing std::function, which does that for you
int main(int argc, char *argv[])
{
unordered_map<string,function<void(void *)>> myHashTable;
MyFirstClass first;
MyFirstClass second;
myHashTable["int"] = [first](void * i) { first.setI(*static_cast<int *>(i)); };
myHashTable["bool"] = [second](void * i) { second.setB(*static_cast<bool *>(i)); };
//
string key = "bool";
bool value = true;
myHashTable[key](static_cast<void *>(&value));
return 0;
}
In std::map, this ends up causing an error when the first object is constructed. I've checked the debugger, and I see that free_list::init() creates the consecutive memory addresses correctly. I'm aware this allocator cannot be used in vector or other related containers, but it's only meant to work with the nodular containers.
I get a run-time error from this in xutility (in VC12), at line 158:
_Container_proxy *_Parent_proxy = _Parent->_Myproxy;
Checking the debugger, it appears that _Parent was never initialized, bringing about the 0xC0000005 run-time error. Why or how it didn't get initialized and why this occurred when the first object was being constructed (after std::map did 3 separate allocations), I do not know.
I would like to have this work with std::map and std::list and the other nodular containers and am not worried about whether it can perform in std::vector, etc.
#include <algorithm>
class free_list {
public:
free_list() {}
free_list(free_list&& other)
: m_next(other.m_next) {
other.m_next = nullptr;
}
free_list(void* data, std::size_t num_elements, std::size_t element_size) {
init(data, num_elements, element_size);
}
free_list& operator=(free_list&& other) {
m_next = other.m_next;
other.m_next = nullptr;
}
void init(void* data, std::size_t num_elements, std::size_t element_size) {
union building {
void* as_void;
char* as_char;
free_list* as_self;
};
building b;
b.as_void = data;
m_next = b.as_self;
b.as_char += element_size;
free_list* runner = m_next;
for (std::size_t s = 1; s < num_elements; ++s) {
runner->m_next = b.as_self;
runner = runner->m_next;
b.as_char += element_size;
}
runner->m_next = nullptr;
}
free_list* obtain() {
if (m_next == nullptr) {
return nullptr;
}
free_list* head = m_next;
m_next = head->m_next;
return head;
}
void give_back(free_list* ptr) {
ptr->m_next = m_next;
m_next = ptr;
}
free_list* m_next;
};
template<class T>
class pool_alloc {
typedef pool_alloc<T> myt;
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef std::false_type propagate_on_container_copy_assignment;
typedef std::true_type propagate_on_container_move_assignment;
typedef std::true_type propagate_on_container_swap;
template<class U> struct rebind {
typedef pool_alloc<U> other;
};
~pool_alloc() {
destroy();
}
pool_alloc() : data(nullptr), fl(), capacity(4096) {
}
pool_alloc(size_type capacity) : data(nullptr), fl(), capacity(capacity) {}
pool_alloc(const myt& other)
: data(nullptr), fl(), capacity(other.capacity) {}
pool_alloc(myt&& other)
: data(other.data), fl(std::move(other.fl)), capacity(other.capacity) {
other.data = nullptr;
}
template<class U>
pool_alloc(const pool_alloc<U>& other)
: data(nullptr), fl(), capacity(other.max_size()) {}
myt& operator=(const myt& other) {
destroy();
capacity = other.capacity;
}
myt& operator=(myt&& other) {
destroy();
data = other.data;
other.data = nullptr;
capacity = other.capacity;
fl = std::move(other.fl);
}
static pointer address(reference ref) {
return &ref;
}
static const_pointer address(const_reference ref) {
return &ref;
}
size_type max_size() const {
return capacity;
}
pointer allocate(size_type) {
if (data == nullptr) create();
return reinterpret_cast<pointer>(fl.obtain());
}
void deallocate(pointer ptr, size_type) {
fl.give_back(reinterpret_cast<free_list*>(ptr));
}
template<class... Args>
static void construct(pointer ptr, Args&&... args) {
::new (ptr) T(std::forward<Args>(args)...);
}
static void destroy(pointer ptr) {
ptr->~T();
}
bool operator==(const myt& other) const {
return reinterpret_cast<char*>(data) ==
reinterpret_cast<char*>(other.data);
}
bool operator!=(const myt& other) const {
return !operator==(other);
}
private:
void create() {
data = ::operator new(capacity * sizeof(value_type));
fl.init(data, capacity, sizeof(value_type));
}
void destroy() {
::operator delete(data);
data = nullptr;
}
void* data;
free_list fl;
size_type capacity;
};
template<>
class pool_alloc < void > {
public:
template <class U> struct rebind { typedef pool_alloc<U> other; };
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
};
The problem comes when std::pair is being constructed (in MSVC12 utility at line 214):
template<class _Other1,
class _Other2,
class = typename enable_if<is_convertible<_Other1, _Ty1>::value
&& is_convertible<_Other2, _Ty2>::value,
void>::type>
pair(_Other1&& _Val1, _Other2&& _Val2)
_NOEXCEPT_OP((is_nothrow_constructible<_Ty1, _Other1&&>::value
&& is_nothrow_constructible<_Ty2, _Other2&&>::value))
: first(_STD forward<_Other1>(_Val1)),
second(_STD forward<_Other2>(_Val2))
{ // construct from moved values
}
Even after stepping in, the run-time error occurs, the same as described above with _Parent not being initialized.
I was able to answer my own question through extensive debugging. Apparently, VC12's std::map implementation at least at times will cast an _Alnod (permanent allocator that stays in scope for the life of the map, which is used to allocate and deallocate the nodes in the map, what I'd expect to be what actually calls allocate() and deallocate()) as an _Alproxy, a temporary allocator which creates some sort of object called _Mproxy (or something like that) using allocate(). The problem, though, is that VC12's implementation then lets _Alproxy go out of scope while still expecting the pointer to the allocated object to remain valid, so it is clear then that I would have to use ::operator new and ::operator delete on an object like _Mproxy: using a memory pool that then goes out of scope while a pointer to a location in it remains is what causes the crash.
I came up with what I suppose could be called a dirty trick, a test that is performed when copy-constructing or copy-assigning an allocator to another allocator type:
template<class U>
pool_alloc(const pool_alloc<U>& other)
: data(nullptr), fl(), capacity(other.max_size()), use_data(true) {
if (sizeof(T) < sizeof(U)) use_data = false;
}
I added the bool member use_data to the allocator class, which if true means to use the memory pool and which if false means to use ::operator new and ::operator delete. By default, it is true. The question of its value arises when the allocator gets cast as another allocator type whose template parameter's size is smaller than that of the source allocator; in that case, use_data is set to false. Because this _Mproxy object or whatever it's called is rather small, this fix seems to work, even when using std::set with char as the element type.
I've tested this using std::set with type char in both VC12 and GCC 4.8.1 in 32-bit and have found that in both cases it works. When allocating and deallocating the nodes in both cases, the memory pool is used.
Here is the full source code:
#include <algorithm>
class free_list {
public:
free_list() {}
free_list(free_list&& other)
: m_next(other.m_next) {
other.m_next = nullptr;
}
free_list(void* data, std::size_t num_elements, std::size_t element_size) {
init(data, num_elements, element_size);
}
free_list& operator=(free_list&& other) {
if (this != &other) {
m_next = other.m_next;
other.m_next = nullptr;
}
return *this;
}
void init(void* data, std::size_t num_elements, std::size_t element_size) {
union building {
void* as_void;
char* as_char;
free_list* as_self;
};
building b;
b.as_void = data;
m_next = b.as_self;
b.as_char += element_size;
free_list* runner = m_next;
for (std::size_t s = 1; s < num_elements; ++s) {
runner->m_next = b.as_self;
runner = runner->m_next;
b.as_char += element_size;
}
runner->m_next = nullptr;
}
free_list* obtain() {
if (m_next == nullptr) {
return nullptr;
}
free_list* head = m_next;
m_next = head->m_next;
return head;
}
void give_back(free_list* ptr) {
ptr->m_next = m_next;
m_next = ptr;
}
free_list* m_next;
};
template<class T>
class pool_alloc {
typedef pool_alloc<T> myt;
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef std::false_type propagate_on_container_copy_assignment;
typedef std::true_type propagate_on_container_move_assignment;
typedef std::true_type propagate_on_container_swap;
myt select_on_container_copy_construction() const {
return *this;
}
template<class U> struct rebind {
typedef pool_alloc<U> other;
};
~pool_alloc() {
clear();
}
pool_alloc() : data(nullptr), fl(), capacity(4096), use_data(true) {}
pool_alloc(size_type capacity) : data(nullptr), fl(),
capacity(capacity), use_data(true) {}
pool_alloc(const myt& other)
: data(nullptr), fl(), capacity(other.capacity),
use_data(other.use_data) {}
pool_alloc(myt&& other)
: data(other.data), fl(std::move(other.fl)), capacity(other.capacity),
use_data(other.use_data) {
other.data = nullptr;
}
template<class U>
pool_alloc(const pool_alloc<U>& other)
: data(nullptr), fl(), capacity(other.max_size()), use_data(true) {
if (sizeof(T) < sizeof(U)) use_data = false;
}
myt& operator=(const myt& other) {
if (*this != other) {
clear();
capacity = other.capacity;
use_data = other.use_data;
}
}
myt& operator=(myt&& other) {
if (*this != other) {
clear();
data = other.data;
other.data = nullptr;
capacity = other.capacity;
use_data = other.use_data;
fl = std::move(other.fl);
}
return *this;
}
template<class U>
myt& operator=(const pool_alloc<U>& other) {
if (this != reinterpret_cast<myt*>(&other)) {
capacity = other.max_size();
if (sizeof(T) < sizeof(U))
use_data = false;
else
use_data = true;
}
return *this;
}
static pointer address(reference ref) {
return &ref;
}
static const_pointer address(const_reference ref) {
return &ref;
}
size_type max_size() const {
return capacity;
}
pointer allocate(size_type) {
if (use_data) {
if (data == nullptr) create();
return reinterpret_cast<pointer>(fl.obtain());
} else {
return reinterpret_cast<pointer>(::operator new(sizeof(T)));
}
}
void deallocate(pointer ptr, size_type) {
if (use_data) {
fl.give_back(reinterpret_cast<free_list*>(ptr));
} else {
::operator delete(reinterpret_cast<void*>(ptr));
}
}
template<class... Args>
static void construct(pointer ptr, Args&&... args) {
::new ((void*)ptr) value_type(std::forward<Args>(args)...);
}
static void destroy(pointer ptr) {
ptr->~value_type();
}
bool operator==(const myt& other) const {
return reinterpret_cast<char*>(data) ==
reinterpret_cast<char*>(other.data);
}
bool operator!=(const myt& other) const {
return !operator==(other);
}
private:
void create() {
size_type size = sizeof(value_type) < sizeof(free_list*) ?
sizeof(free_list*) : sizeof(value_type);
data = ::operator new(capacity * size);
fl.init(data, capacity, size);
}
void clear() {
::operator delete(data);
data = nullptr;
}
void* data;
free_list fl;
size_type capacity;
bool use_data;
};
template<>
class pool_alloc < void > {
public:
template <class U> struct rebind { typedef pool_alloc<U> other; };
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
};
template<class Container, class Alloc>
void change_capacity(Container& c, typename Alloc::size_type new_capacity) {
Container temp(c, Alloc(new_capacity));
c = std::move(temp);
}
Since the allocator is not automatic-growing (don't know how to make such a thing), I have added the change_capacity() function.
The find method of boost::splay_set that require only the key accepts an argument of type KeyValueCompare to compare objects with the key. To be able to use this, we need to supply two methods of the form:
struct KeyValCompare {
inline bool operator() (const std::int64_t key, const MyType& val) const {
//TODO:
}
inline bool operator() (const MyType& val, const std::int64_t key) const {
//TODO:
}
};
However there is no mention in the documentation about how to implement these. Any pointers?
Found a solution here:
http://boost.cowic.de/rc/pdf/intrusive.pdf
they should return true if key (or key from the value) of lhs is less than the key (or key from the value) of rhs.
I don't see why the comparator would be so complicated. The set just stores elements of MyType, so you need to define a strict weak total ordering on them:
struct Comparator {
bool operator()(MyType const& a, MyType const& b) const;
};
Indeed, the default comparer is std::less<MyType>
E.g. to sort
class MyType : public splay_set_base_hook<>
{
int int_;
public:
MyType(int i) : int_(i) {}
int getValue() const { return int_; }
};
By the value, after reversing the digits (e.g. "431" before "322" because 134<223):
struct CompareReversed {
bool operator()(MyType const& a, MyType const& b) const {
return reversed(a.getValue()) < reversed(b.getValue());
}
private:
static int reversed(int i)
{
auto s = std::to_string(i);
std::reverse(s.begin(), s.end());
return boost::lexical_cast<int>(s);
}
};
See it Live On Coliru:
#include <boost/intrusive/splay_set.hpp>
#include <boost/lexical_cast.hpp>
#include <vector>
#include <algorithm>
using namespace boost::intrusive;
class MyType : public splay_set_base_hook<>
{
int int_;
public:
MyType(int i) : int_(i)
{}
// default ordering
friend bool operator< (const MyType &a, const MyType &b) { return a.int_ < b.int_; }
friend bool operator> (const MyType &a, const MyType &b) { return a.int_ > b.int_; }
friend bool operator== (const MyType &a, const MyType &b) { return a.int_ == b.int_; }
int getValue() const { return int_; }
};
struct CompareReversed {
bool operator()(MyType const& a, MyType const& b) const {
return reversed(a.getValue()) < reversed(b.getValue());
}
private:
static int reversed(int i)
{
auto s = std::to_string(i);
std::reverse(s.begin(), s.end());
return boost::lexical_cast<int>(s);
}
};
#include <iostream>
int main()
{
//typedef splay_set<MyType, compare<std::less<MyType> > > Set;
typedef splay_set<MyType, compare<CompareReversed> > Set;
std::vector<MyType> v { 24, 42, 123, 321 };
Set set;
set.insert(v[0]);
set.insert(v[1]);
set.insert(v[2]);
set.insert(v[3]);
for (auto& el : set)
{
std::cout << el.getValue() << "\n";
}
std::cout << set.count(24) << "\n"; // 1
std::cout << set.count(25) << "\n"; // 0
std::cout << set.count(42) << "\n"; // 1
}
If you want to suppor mixed type comparisons, just supply the overloads, obviously:
struct CompareReversed {
bool operator()(MyType const& a, MyType const& b) const {
return reversed(a.getValue()) < reversed(b.getValue());
}
bool operator()(MyType const& a, int b) const {
return reversed(a.getValue()) < reversed(b);
}
bool operator()(int a, MyType const& b) const {
return reversed(a) < reversed(b.getValue());
}
// ...
};
Thanks sehe for the support.
That is exactly what I am doing there. But please have a look at following sample code which fails.
#include <boost/intrusive/splay_set.hpp>
#include <algorithm>
using namespace boost::intrusive;
class MyClass {
public:
MyClass(const std::int64_t& k)
: key(k) {
}
std::int64_t key;
splay_set_member_hook<> member_hook_;
friend bool operator <(const MyClass& lhs, const MyClass& rhs) {
return lhs.key < rhs.key;
}
friend bool operator >(const MyClass& lhs, const MyClass& rhs) {
return lhs.key > rhs.key;
}
friend bool operator ==(const MyClass& lhs, const MyClass& rhs) {
return lhs.key == rhs.key;
}
};
struct KeyValCompare {
inline bool operator()(const std::int64_t key, const MyClass& val) const {
return key < val.key;
}
inline bool operator()(const MyClass& val, const std::int64_t key) const {
return val.key < key;
}
};
typedef member_hook<MyClass, splay_set_member_hook<>, &MyClass::member_hook_> MemberOption;
typedef splay_set<MyClass, MemberOption, compare<std::greater<MyClass> > > MyClassObjectsType;
TEST(MyClass, test) {
MyClassObjectsType set;
set.insert(*new MyClass(10));
set.insert(*new MyClass(20));
set.insert(*new MyClass(100));
auto ite = set.find(100, KeyValCompare());
ASSERT_TRUE(ite != set.end()); // Fails here
}
If I use std::less instead of std::greater, it passes.
Figured it out:
The greater than operator must be change from:
friend bool operator >(const MyClass& lhs, const MyClass& rhs) {
return lhs.key > rhs.key;
}
to this:
friend bool operator >(const MyClass& lhs, const MyClass& rhs) {
return lhs.key < rhs.key;
}
Here is a code I do have on Visual 2013.
I need to have an aligned new.
I can not allocate only because A CTOR does something useful.
Any idea of why this does not compile ?
#include <memory>
#include <emmintrin.h>
struct A{
A():b(0){b++;}
int b;
};
template<typename T,int alignment>
inline T* aligned_new(){
try{
T*ptr = reinterpret_cast<T*>(_mm_malloc(sizeof(T),alignment));
new (ptr) T;
return ptr;
}
catch (...)
{
return nullptr;
}
}
template<typename T>
inline void aligned_delete(T*ptr){
_mm_free(ptr);
}
int main(int argc, char * argv[]){
std::unique_ptr<A, aligned_delete<A>> var(aligned_new<A,16>);
return 0;
}
solution
template<typename T>
struct aligned_delete {
void operator()(T* ptr) const {
_mm_free(ptr);
}
};
aligned_delete<A> is a function, not a type.
Make a type with an overloaded function call operator:
template<typename T>
struct aligned_delete {
void operator()(T* ptr) const {
_mm_free(ptr);
}
};
Your exception handling is a bit off, you will leak the allocated memory if construction fails. It also has undefined behavior if _mm_malloc returns nullptr. Try:
template<typename T, std::size_t alignment>
inline T* aligned_new(){
void* ptr = _mm_malloc(sizeof(T), alignment);
if (ptr) {
try {
return new (ptr) T;
} catch(...) {
_mm_free(ptr);
throw;
}
}
// throw std::bad_alloc();
return nullptr;
}
(Yes, this is not an answer - it's an overlong comment.)