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.
Related
In real applications I should stick to the standard library facilities, for practice and understanding how those facilities work I should try to implement my own.
Here I've implemented a simulation of the smart pointer unique_ptr:
#include<iostream>
#include <memory>
template <typename T>
class DefDel
{
public:
template <typename U>
void operator()(U* p)const
{
std::cout << "freeing memory...\n";
delete p;
}
};
template <typename T>
class DefDel<T[]>
{
public:
template <typename U>
void operator()(U* p)const
{
std::cout << "freeing memory of an array of objects...\n";
delete[] p;
}
};
template <typename T, typename D = DefDel<T>>
class UniqPtr final
{
public:
UniqPtr(T* = nullptr, D = DefDel<T>{});
UniqPtr(UniqPtr const&) = delete;
UniqPtr(UniqPtr&&) noexcept;
UniqPtr& operator =(UniqPtr const&) = delete;
UniqPtr& operator =(UniqPtr&&) noexcept;
~UniqPtr();
T& operator*();
T const& operator*() const;
T* operator->();
T const* operator->() const;
operator bool() const;
private:
T* ptr_{nullptr};
D del_{};
};
template <typename T, typename D>
UniqPtr<T, D>::UniqPtr(T* p, D del) :
ptr_(p),
del_(del)
{}
template <typename T, typename D>
UniqPtr<T, D>::UniqPtr(UniqPtr&& rhs) noexcept :
ptr_(std::move(rhs.ptr_)),
del_(std::move(rhs.del_))
{
rhs.ptr_ = nullptr;
}
template <typename T, typename D>
UniqPtr<T, D>& UniqPtr<T, D>::operator = (UniqPtr&& rhs) noexcept
{
if(this != &rhs)
{
ptr_ = std::move(rhs.ptr_);
del_ = std::move(rhs.del_);
rhs.ptr_ = nullptr;
}
return *this;
}
template <typename T, typename D>
UniqPtr<T, D>::~UniqPtr()
{
del_(ptr_);
}
template <typename T, typename D>
T& UniqPtr<T, D>::operator*()
{
return *ptr_;
}
template <typename T, typename D>
T const& UniqPtr<T, D>::operator*() const
{
return *ptr_;
}
template <typename T, typename D>
T* UniqPtr<T, D>::operator->()
{
return ptr_;
}
template <typename T, typename D>
T const* UniqPtr<T, D>::operator->() const
{
return ptr_;
}
template <typename T, typename D>
UniqPtr<T, D>::operator bool() const
{
return ptr_;
}
// for array
template <typename T, typename D>
class UniqPtr<T[], D> final
{
public:
UniqPtr(T* = nullptr, D = DefDel<T[]>{});
UniqPtr(UniqPtr const&) = delete;
UniqPtr(UniqPtr&&) noexcept;
UniqPtr& operator =(UniqPtr const&) = delete;
UniqPtr& operator =(UniqPtr&&) noexcept;
~UniqPtr();
T& operator*();
T const& operator*() const;
T* operator->();
T const* operator->() const;
operator bool() const;
private:
T* ptr_{nullptr};
D del_{};
};
template <typename T, typename D>
UniqPtr<T[], D>::UniqPtr(T* p, D del) :
ptr_(p),
del_(del)
{}
template <typename T, typename D>
UniqPtr<T[], D>::UniqPtr(UniqPtr&& rhs) noexcept :
ptr_(std::move(rhs.ptr_)),
del_(std::move(rhs.del_))
{
rhs.ptr_ = nullptr;
}
template <typename T, typename D>
UniqPtr<T[], D>& UniqPtr<T[], D>::operator = (UniqPtr&& rhs) noexcept
{
if(this != &rhs)
{
ptr_ = std::move(rhs.ptr_);
del_ = std::move(rhs.del_);
rhs.ptr_ = nullptr;
}
return *this;
}
template <typename T, typename D>
UniqPtr<T[], D>::~UniqPtr()
{
del_(ptr_);
}
template <typename T, typename D>
T& UniqPtr<T[], D>::operator*()
{
return *ptr_;
}
template <typename T, typename D>
T const& UniqPtr<T[], D>::operator*() const
{
return *ptr_;
}
template <typename T, typename D>
T* UniqPtr<T[], D>::operator->()
{
return ptr_;
}
template <typename T, typename D>
T const* UniqPtr<T[], D>::operator->() const
{
return ptr_;
}
template <typename T, typename D>
UniqPtr<T[], D>::operator bool() const
{
return ptr_;
}
int main()
{
UniqPtr<int[]> upi(new int[3]{57});
std::cout << sizeof(upi) << '\n';
std::unique_ptr<int[], DefDel<int[]>> upi2(new int[3]{57});
std::cout << sizeof(upi2) << '\n';
}
Why the size of my UniqPtr objects are double in size as std::unique_ptr (even being initialized with the same values)?
Is that because of my class is storing a Del_ object as a member?
If that is the problem then how could I achieve the very similar behavior as unique_ptr with 0 cost?
Why the size of my UniqPtr objects are double in size as std::unique_ptr (even being initialized with the same values)?
Is that because of my class is storing a Del_ object as a member?
Yes.
Because D del_ needs to have storage, and every T* ptr_ has to be properly aligned
If that is the problem then how could I achieve the very similar behavior as unique_ptr with 0 cost?
You can privately derive from D, rather than have it be a member. Then an instantiation with an empty class may cave it occupy no extra storage.
template <typename T, typename D = DefDel<T>>
class UniqPtr final : D
{
public:
UniqPtr(T* = nullptr, D = {});
UniqPtr(UniqPtr const&) = delete;
UniqPtr(UniqPtr&&) noexcept;
UniqPtr& operator =(UniqPtr const&) = delete;
UniqPtr& operator =(UniqPtr&&) noexcept;
~UniqPtr();
T& operator*();
T const& operator*() const;
T* operator->();
T const* operator->() const;
operator bool() const;
private:
T* ptr_{nullptr};
};
template <typename T, typename D>
UniqPtr<T, D>::UniqPtr(T* p, D del) :
D(del),
ptr_(p)
{}
template <typename T, typename D>
UniqPtr<T, D>::UniqPtr(UniqPtr&& rhs) noexcept :
D(std::move(*rhs)),
ptr_(std::exchange(rhs.ptr_, nullptr))
{}
template <typename T, typename D>
UniqPtr<T, D>& UniqPtr<T, D>::operator = (UniqPtr&& rhs) noexcept
{
using std::swap;
swap(static_cast<D&>(*this), static_cast<D&>(rhs));
swap(ptr_, rhs.ptr_);
}
template <typename T, typename D>
UniqPtr<T, D>::~UniqPtr()
{
static_cast<D&>(*this)(ptr_);
}
Let's say we store a struct with a string key and we want to find it by that string in a container like std::set, so common implementation would look like this:
struct Foo {
std::string id;
};
struct FooComp {
using is_transparent = std::true_type;
bool operator()( const Foo &foo, const std::string &str ) const
{
return foo.id < str;
}
bool operator()( const std::string &str, const Foo &foo ) const
{
return str < foo.id;
}
bool operator()( const Foo &foo1, const Foo &foo2 ) const
{
return foo1.id < foo2.id;
}
};
std::set<Foo,FooComp> foo_set;
...
This works fine, but writing three methods for FooComp that do prety match the same (logically) is monotonic and error prone. Is there a way to minimize that code?
You may do as following:
struct Foo {
std::string id;
};
struct FooComp {
using is_transparent = std::true_type;
template <typename LHS, typename RHS>
bool operator()(const LHS& lhs, const RHS& rhs) const
{
return ProjectAsId(lhs) < ProjectAsId(rhs);
}
private:
const std::string& ProjectAsId(const std::string& s) const { return s; }
const std::string& ProjectAsId(const Foo& foo) const { return foo.id; }
};
You write comparison once, but you have to write the projection for each type.
In C++17, it can even be
template <auto f> struct ProjLess
{
using is_transparent = std::true_type;
template <typename LHS, typename RHS>
bool operator()(const LHS& lhs, const RHS& rhs) const
{
return project(lhs) < project(rhs);
}
private:
template <typename T>
using f_t = decltype(std::invoke(f, std::declval<const T&>()));
template <typename T>
using is_f_callable = is_detected<f_t, T>;
template <typename T, std::enable_if_t<is_f_callable<T>::value>* = nullptr>
decltype(auto) project(const T& t) const { return std::invoke(f, t); }
template <typename T, std::enable_if_t<!is_f_callable<T>::value>* = nullptr>
const T& project(const T& t) const { return t; }
};
And usage:
std::set<Foo, ProjLess<&Foo::id>> s;
Demo with C++17
My solution is all in the class:
struct FooComp {
using is_transparent = std::true_type;
struct FooProj {
std::string const& str;
FooProj( std::string const& sin ):str(sin) {}
FooProj( const Foo& foo ):str(foo.id) {}
FooProj( FooProj const& ) = default;
friend bool operator<(FooProj lhs, FooProj rhs) {
return lhs.str < rhs.str;
}
};
bool operator()( FooProj lhs, FooProj rhs ) const
{
return lhs<rhs;
}
};
This doesn't support types that can convert to std::string.
However, when doing a projection-based comparison, I do this:
template<class F, class After=std::less<>>
auto order_by( F&& f, After&& after={} ) {
return
[f=std::forward<F>(f), after=std::forward<After>(after)]
(auto&& rhs, auto&&lhs)->bool {
return after( f(decltype(lhs)(lhs)), f(decltype(rhs)(rhs)) );
};
}
which takes a projection and generates a comparison function for it. We make it transparent with:
template<class F>
struct as_transparent_t {
F f;
using is_transparent=std::true_type;
template<class Lhs, class Rhs>
bool operator(Lhs const& lhs, Rhs const& rhs)const{ return f(lhs, rhs); }
};
template<class F>
as_transparent_f<std::decay_t<F>>
as_transparent( F&& f ) { return {std::forward<F>(f)}; }
so we can project and be transparent via:
as_transparent( order_by( some_projection ) );
which only leaves the projection.
In C++14 we just do a
std::string const& foo_proj_f( std::string const& str ) { return str; }
std::string const& foo_proj_f( Foo const& foo ) { return foo.id; }
auto foo_proj = [](auto const& x)->decltype(auto){ return foo_proj_f(x); };
auto foo_order = as_transparent( order_by( foo_proj ) );
which breaks things down into modular chunks.
In C++17 we can use if constexpr:
auto foo_proj = [](auto const& x)->std::string const& {
if constexpr( std::is_same<decltype(x), std::string const&>{} ) {
return x;
}
if constexpr( std::is_same<decltype(x), Foo const&>{} ) {
return x.id;
}
};
auto foo_order = as_transparent( order_by( foo_proj ) );
or
template<class...Ts>
struct overloaded:Ts...{
using Ts::operator()...;
overloaded(Ts...ts):Ts(std::move(ts)...){}
};
template<class...Ts> overloaded -> overloaded<Ts...>;
which permits
auto foo_proj = overloaded{
[](std::string const& s)->decltype(auto){return s;},
[](Foo const& f)->decltype(auto){return f.id;}
};
which may be easier to read than the if constexpr version. (This version can also be adapted to c++14 or c++11).
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 have encountered a strange problem, that I don't know how to solve in overloading.
Im trying too overload operator == .
The easy example would be:
class bla{
public:
int a;
void bla(int a):a(a){}//costructor
bool operator==(const bla& ob)
return (a==ob.a);//chk if equal
};
void main(){
bla A,B;
if (A==B)
flag=1;//just an example...
this is easy and works great, i'm trying to handle the case of:
if (A==B==C==D)
so i need to return type object and now type bool.
i have tried to add another function :
bla &bla:: operator==(const bool answer){//as a member function
if (answer)
return *this;
but it doesn't seem to help. have any suggestions?
thx Stas
This is a horrible idea and you should never do it.
Here is how you do it.
#include <type_traits>
template<typename T, typename U>
struct decay_equiv
: std::is_same<
typename std::decay<T>::type,
typename std::decay<U>::type
>::type {};
template<typename T>
struct comparator {
bool res;
T passalong;
explicit operator bool() { return res; }
typename std::enable_if<
!decay_equiv<T, comparator<T> >::value,
comparator<T>
>::type operator==(T const& rhs);
comparator<T> operator==(comparator<T> const& rhs);
};
template<typename T>
typename std::enable_if<
!decay_equiv<T, comparator<T>>::value,
comparator<T>
>::type comparator<T>::operator==(T const& rhs) {
if (!res) {
return {res, rhs};
}
return {(passalong == rhs).res, rhs};
}
template<typename T>
comparator<T> comparator<T>::operator==(comparator<T> const& rhs) {
if (!res || !rhs.res) {
return {res, rhs};
}
return {(passalong == rhs.passalong).res, rhs.passalong};
}
struct bla {
int a;
comparator<bla> operator==(bla const& rhs);
comparator<bla> operator==(comparator<bla> const& rhs);
};
comparator<bla> bla::operator==(bla const& rhs) {
return {a == rhs.a, rhs};
}
comparator<bla> bla::operator==(comparator<bla> const& rhs) {
if (!rhs.res) {
return rhs;
}
return {a == rhs.passalong.a, rhs.passalong};
}
int main() {
bla a = {0},b = {0},d = {0};
if (a==b==d)
return 0;
return -1;
}
This code assumes C++11, but can be written in C++98 with only very minor changes.
i have managed to find a different approach and it seems to work great.
thx to u all for your help and suggestions.
class bla{
public:
int a;
bool f;
void bla(int a):a(a){f = true;}//costructor
operator bool(){return f};
bla& operator==(const bla &ob){//chk if equal
if (f)
f=(a==ob.a);
return *this;
}
};
void main(){
bla A(4),B(4),C(4),D(4);
if (A==B==C==D)
flag=1;//just an example...
I am a bit new to templates in C++ so forgive me if this question is confusing or stupid, I just have a problem where I want to implement a clone smart pointer so I don't have to create copy constructors for each and every class that uses my underlying XML library that only seems to use object pointers and not smart pointers. The problem is that my traits need to create the new objects using functions from the underlying library and I do not know how I would go about doing that in a template/traits class. I have posted all the code with some comments below, if anybody could advice, I'd appreciate it.
If something is unclear, please ask and I will try to clarify.
#ifndef CLONE_PTR_H
#define CLONE_PTR_H
#include <algorithm>
#include <functional>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMDocument.hpp>
struct DOMObject_cloner
{
static DOMDocument* clone(DOMDocument* pPtr)
{
DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(X("Core")); // this looks wrong, depends on DOMIMplementation_cloner being done really... how do I do this properly
return pPtr ? : impl->createDocument(...) //I need this function for a DOMDocument* to be created!!!
}
};
struct DOMImplementation_cloner
{
static DOMImplementation* clone(DOMImplementation* pPtr)
{
return pPtr ? DOMImplementationRegistry::getDOMImplementation(X("Core")) : 0;
}
};
template<typename T>
struct default_clone
{
static T* clone(T* pPtr)
{
return pPtr ? pPtr->clone() : 0;
}
};
template <typename T, typename Cloner = default_clone<T> >
class clone_ptr
{
public:
// types
typedef T element_type;
typedef element_type value_type;
typedef const element_type const_value_type;
typedef value_type* pointer;
typedef const_value_type* const_pointer;
typedef value_type& reference;
typedef const_value_type& const_reference;
// creation
clone_ptr() :
mPtr(0)
{}
explicit clone_ptr(pointer pPtr) :
mPtr(pPtr)
{}
clone_ptr(const clone_ptr& pOther) :
mPtr(pOther.get() ? Cloner()(pOther.get()) : 0)
{}
/*clone_ptr(const clone_ptr& pOther) :
mPtr(pOther.get() ? pOther->clone() : 0),
{}*/
clone_ptr& operator=(clone_ptr pOther)
{
swap(*this, pOther);
return *this;
}
~clone_ptr()
{
delete get();
}
// observers
pointer get() const
{
return mPtr;
}
pointer operator->() const
{
return get();
}
reference operator*() const
{
assert(get() != 0);
return *get();
}
// modifiers
pointer release()
{
pointer result = mPtr;
mPtr = 0;
return result;
}
void reset(pointer pPtr = 0)
{
*this = clone_ptr(pPtr);
}
// utility
friend void swap(clone_ptr& pFirst, clone_ptr& pSecond)
{
std::swap(pFirst.mPtr, pSecond.mPtr);
}
private:
pointer mPtr;
//default_clone Cloner;
};
template <typename T1>
bool operator!(const clone_ptr<T1>& pX)
{
return pX.get() == 0;
};
template <typename T1, typename T2>
bool operator>=(const clone_ptr<T1>& pFirst, const clone_ptr<T2>& pSecond)
{
return !(pFirst < pSecond);
};
// compare
template <typename T1, typename T2>
bool operator==(const clone_ptr<T1>& pFirst, const clone_ptr<T2>& pSecond)
{
return pFirst.get() == pSecond.get();
};
template <typename T1, typename T2>
bool operator!=(const clone_ptr<T1>& pFirst, const clone_ptr<T2>& pSecond)
{
return !(pFirst == pSecond);
};
template <typename T1, typename T2>
bool operator<(const clone_ptr<T1>& pFirst, const clone_ptr<T2>& pSecond)
{
return std::less<void*>()(pFirst.get(), pSecond.get());
};
template <typename T1, typename T2>
bool operator<=(const clone_ptr<T1>& pFirst, const clone_ptr<T2>& pSecond)
{
return !(pFirst > pSecond);
};
template <typename T1, typename T2>
bool operator>(const clone_ptr<T1>& pFirst, const clone_ptr<T2>& pSecond)
{
return pSecond < pFirst;
};
#endif
I am not really sure if I understand your question, but I see one thing wrong with your code. DOMObject_cloner and DOMImplementation_cloner should be specializations of default_clone, like this:
template<>
struct default_clone<DOMDocument> {
static DOMDocument* clone(DOMDocument* pPtr)
{
DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(X("Core"));
return pPtr ? : impl->createDocument(...);
}
};
Template specialization is the whole point of traits in C++.