std::bind and boost::bind tricks - c++11

#include <functional>
#include <boost/bind.hpp>
class A
{
public:
A(){}
~A(){}
template<typename _Handler>
void call_handler(_Handler handler)
{
handler();
}
};
class B
{
public:
template<typename _Handler>
void call_handler(_Handler handler)
{
}
template<typename _Handler>
void run(_Handler handler)
{
m_a.call_handler(boost::bind(&B::call_handler<_Handler>, this, handler));
//only can use boost::bind here
}
A m_a;
};
class Test
{
public:
void handler()
{
}
};
int main()
{
B b;
Test t;
b.run(boost::bind(&Test::handler,&t));//only can use std::bind here
}
this is my little test code above.
I am confused that I only can use bind in the specific order...see note above
if I change std::bind to boost::bind ,then compiler failed,vice versa.
tested with:
gcc 4.9.2 for cygwin with option:
g++ -std=c++11 -fdiagnostics-color=always -fdiagnostics-show-location=every-line -I"/cygdrive/e/opensource libs/boost" main.cpp
msvc 12.0(visual studio 2013 with update4) with default option.
gcc diagnostic messages:
In file included from /cygdrive/e/opensource
libs/boost/boost/bind.hpp:22:0,
from main.cpp:3: /cygdrive/e/opensource libs/boost/boost/bind/bind.hpp: In instantiation of ‘void
boost::_bi::list2::operator()(boost::_bi::type, F&, A&,
int) [with F = boost::_mfi::mf1,
boost::_bi::list1 > > >; A =
boost::_bi::list0; A1 = boost::_bi::value; A2 =
boost::_bi::bind_t,
boost::_bi::list1 > >]’:
/cygdrive/e/opensource libs/boost/boost/bind/bind.hpp:893:50:
required from ‘boost::_bi::bind_t::result_type
boost::_bi::bind_t::operator()() [with R = void; F =
boost::_mfi::mf1,
boost::_bi::list1 > > >; L =
boost::_bi::list2, boost::_bi::bind_t,
boost::_bi::list1 > > >;
boost::_bi::bind_t::result_type = void]’ main.cpp:12:11:
required from ‘void A::call_handler(_Handler) [with _Handler =
boost::_bi::bind_t,
boost::_bi::list1 > > >,
boost::_bi::list2, boost::_bi::bind_t,
boost::_bi::list1 > > > >]’ main.cpp:27:3:
required from ‘void B::run(_Handler) [with _Handler =
boost::_bi::bind_t,
boost::_bi::list1 > >]’ main.cpp:44:38:
required from here /cygdrive/e/opensource
libs/boost/boost/bind/bind.hpp:313:34: error: invalid use of void
expression
unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]);
^
msvc 12.0 diagnostic messages:
1>------ Build started: Project: scince_x32, Configuration: Debug
Win32 ------ 1> main.cpp 1>e:\opensource
libs\boost\boost\bind\bind.hpp(313): error C2664: 'void
boost::_mfi::mf1::operator ()(T *,A1) const' : cannot
convert argument 2 from 'void' to
'boost::_bi::bind_t,boost::_bi::list1>>'
1> with 1> [ 1>
_Handler=boost::_bi::bind_t,boost::_bi::list1>> 1> , T=B 1> , A1=boost::_bi::bind_t,boost::_bi::list1>> 1> ] 1> and 1> [ 1> T=Test * 1> ] 1> Expressions of type void cannot be
converted to other types 1> e:\opensource
libs\boost\boost\bind\bind.hpp(893) : see reference to function
template instantiation 'void
boost::_bi::list2,boost::_bi::bind_t,boost::_bi::list1>>>::operator
()(boost::_bi::type,F &,A &,int)' being
compiled 1> with 1> [ 1> T=B * 1> ,
F=boost::_mfi::mf1,boost::_bi::list1>>> 1> , A=boost::_bi::list0 1> ] 1> e:\opensource libs\boost\boost\bind\bind.hpp(893) : see reference to
function template instantiation 'void
boost::_bi::list2,boost::_bi::bind_t,boost::_bi::list1>>>::operator
()(boost::_bi::type,F &,A &,int)' being
compiled 1> with 1> [ 1> T=B * 1> ,
F=boost::_mfi::mf1,boost::_bi::list1>>> 1> , A=boost::_bi::list0 1> ] 1> e:\opensource libs\boost\boost\bind\bind.hpp(891) : while compiling
class template member function 'void
boost::_bi::bind_t,boost::_bi::list2,boost::_bi::bind_t,boost::_bi::list1>>>>::operator
()(void)' 1> with 1> [ 1>
_Handler=boost::_bi::bind_t,boost::_bi::list1>> 1> , T=B * 1> ] 1> e:\c++program\scince_x32\scince_x32\main.cpp(12) : see reference to
function template instantiation 'void
boost::_bi::bind_t,boost::_bi::list2,boost::_bi::bind_t,boost::_bi::list1>>>>::operator
()(void)' being compiled 1> with 1> [ 1>
_Handler=boost::_bi::bind_t,boost::_bi::list1>> 1> , T=B * 1> ] 1> e:\c++program\scince_x32\scince_x32\main.cpp(27) : see reference to
class template instantiation
'boost::_bi::bind_t,boost::_bi::list2,boost::_bi::bind_t,boost::_bi::list1>>>>'
being compiled 1> with 1> [ 1>
_Handler=boost::_bi::bind_t,boost::_bi::list1>> 1> , T=B * 1> ] 1> e:\c++program\scince_x32\scince_x32\main.cpp(44) : see reference to
function template instantiation 'void
B::run,boost::_bi::list1>>>(_Handler)'
being compiled 1> with 1> [ 1> T=Test *
1> ,
_Handler=boost::_bi::bind_t,boost::_bi::list1>> 1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

You're (indirectly) binding a bind-expression that binds as an argument another bind-expression.
In both Boost and standard library you need to protect the inner bind-expression so that the placeholders/bindings don't mix and conflict.
So it would begin with
m_a.call_handler(boost::bind(&B::call_handler<_Handler>, this, boost::protect(handler)));
Except, the protect(handler) wraps the type and it's no longer _Handler, so you need something else for &B::call_handler<???>. In my experience, the easiest by far, is to use a polymorphic function object:
struct handler_caller_f {
typedef void result_type;
template <typename H> void operator()(B* /*this_*/, H/* handler*/) const {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
template <typename H> void run(H handler) {
m_a.call_handler(boost::bind(handler_caller_f(), this, boost::protect(handler)););
}
As you can see the function object replaces B::call_handler and removes the problem by deducing the type of handler again.
Here's a cleaned up version:
Using Boost
Live On Coliru
#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
#include <iostream>
struct A {
template <typename H> void call_handler(H handler) {
handler();
}
};
struct B {
struct handler_caller_f {
typedef void result_type;
template <typename H> void operator()(B* this_, H handler) const {
handler();
}
};
template <typename H> void run(H handler) {
m_a.call_handler(boost::bind(handler_caller_f(), this, boost::protect(handler)));
}
A m_a;
};
struct Test {
void handler() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
int main() {
Test t;
B b;
b.run(boost::bind(&Test::handler, &t));
}
Prints
void Test::handler()
Using std::bind
Standard library doesn't have protect, but it's easy to add:
Live On Coliru
#include <functional>
#include <iostream>
namespace std_ex { // http://stackoverflow.com/questions/18519087/why-is-there-no-stdprotect
template <typename T> struct protect_wrapper : T {
protect_wrapper(const T &t) : T(t) {}
protect_wrapper(T &&t) : T(std::move(t)) {}
};
template <typename T>
typename std::enable_if<!std::is_bind_expression<typename std::decay<T>::type>::value, T && >::type protect(T &&t) {
return std::forward<T>(t);
}
template <typename T>
typename std::enable_if<std::is_bind_expression<typename std::decay<T>::type>::value,
protect_wrapper<typename std::decay<T>::type> >::type
protect(T &&t) {
return protect_wrapper<typename std::decay<T>::type>(std::forward<T>(t));
}
}
struct A {
template <typename H> void call_handler(H handler) { handler(); }
};
struct B {
struct handler_caller_f {
typedef void result_type;
template <typename H> void operator()(B *this_, H handler) const { handler(); }
};
template <typename H> void run(H handler) {
m_a.call_handler(std::bind(handler_caller_f(), this, std_ex::protect(handler)));
}
A m_a;
};
struct Test {
void handler() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
int main() {
Test t;
B b;
b.run(std::bind(&Test::handler, &t));
}

Related

Need help linking code using Boost rtree for storing user-defined object in tree where object contains the indexable -a boost geometry box

I have a hard time following the C++ template and stl code of the open source boost library and hope someone can help with my code sample that tries to store a user defined object (Node) in a boost::geometry::index::rtree. The Node object contains the indexable and I am trying to define an indexable object that translates the Node to a box (retrieves the box member of Node).
I am using Visual Studio Express 2022 and Boost 1.79.0 under Windows 10.
This is the link error:
Microsoft (R) Build Engine version 17.0.0+c9eb9dd64 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
Automatic MOC and UIC for target BoostNodeTree
BoostNodeTree.cpp
E:\boost_1_79_0\boost/geometry/index/detail/translator.hpp(62,1): error C2662: 'const boost::geometry::index::node_indexable::result_type &boost::geometry::index::node_indexable::operator ()(const Node &)': cannot convert 'this' pointer from 'const boost::geometry::index::detail::translator<IndexableGetter,EqualTo>' to 'boost::geometry::index::node_indexable &' [C:\Users\Lawrence Travis\source\repos\BoostNodeTree\build\BoostNodeTree.vcxproj]
with
[
IndexableGetter=NodeTree::indexable_getter,
EqualTo=NodeTree::equal_to_getter
]
E:\boost_1_79_0\boost/geometry/index/detail/translator.hpp(62,33): message : Conversion loses qualifiers [C:\Users\Lawrence Travis\source\repos\BoostNodeTree\build\BoostNodeTree.vcxproj]
C:\Users\Lawrence Travis\source\repos\BoostNodeTree\NodeTree.h(22,36): message : see declaration of 'boost::geometry::index::node_indexable::operator ()' [C:\Users\Lawrence Travis\source\repos\BoostNodeTree\build\BoostNodeTree.vcxproj]
E:\boost_1_79_0\boost/geometry/index/rtree.hpp(1655): message : see reference to function template instantiation 'boost::geometry::model::box<point_t> boost::geometry::index::detail::translator<IndexableGetter,EqualTo>::operator ()<Node>(const Value &) const' being compiled [C:\Users\Lawrence Travis\source\repos\BoostNodeTree\build\BoostNodeTree.vcxproj]
with
[
IndexableGetter=NodeTree::indexable_getter,
EqualTo=NodeTree::equal_to_getter,
Value=Node
]
E:\boost_1_79_0\boost/geometry/index/rtree.hpp(1655): message : see reference to function template instantiation 'boost::geometry::model::box<point_t> boost::geometry::index::detail::translator<IndexableGetter,EqualTo>::operator ()<Node>(const Value &) const' being compiled [C:\Users\Lawrence Travis\source\repos\BoostNodeTree\build\BoostNodeTree.vcxproj]
with
[
IndexableGetter=NodeTree::indexable_getter,
EqualTo=NodeTree::equal_to_getter,
Value=Node
]
E:\boost_1_79_0\boost/geometry/index/rtree.hpp(1652): message : while compiling class template member function 'void boost::geometry::index::rtree<NodeTree::value,NodeTree::parameters,NodeTree::indexable_getter,NodeTree::equal_to_getter,boost::container::new_allocator<Value>>::raw_insert(const Node &)' [C:\Users\Lawrence Travis\source\repos\BoostNodeTree\build\BoostNodeTree.vcxproj]
with
[
Value=NodeTree::value
]
E:\boost_1_79_0\boost/geometry/index/rtree.hpp(832): message : see reference to function template instantiation 'void boost::geometry::index::rtree<NodeTree::value,NodeTree::parameters,NodeTree::indexable_getter,NodeTree::equal_to_getter,boost::container::new_allocator<Value>>::raw_insert(const Node &)' being compiled [C:\Users\Lawrence Travis\source\repos\BoostNodeTree\build\BoostNodeTree.vcxproj]
with
[
Value=NodeTree::value
]
C:\Users\Lawrence Travis\source\repos\BoostNodeTree\NodeTree.h(56): message : see reference to class template instantiation 'boost::geometry::index::rtree<NodeTree::value,NodeTree::parameters,NodeTree::indexable_getter,NodeTree::equal_to_getter,boost::container::new_allocator<Value>>' being compiled [C:\Users\Lawrence Travis\source\repos\BoostNodeTree\build\BoostNodeTree.vcxproj]
with
[
Value=NodeTree::value
]
Here is the code and thanks in advance for any help!
Node.h:
#pragma once
#include <Windows.h>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
typedef bg::model::point<int, 2, bg::cs::cartesian> point_t;
typedef bg::model::box<point_t> box_t;
using namespace std;
class Node
{
public:
typedef Node value_type;
typedef const value_type& const_reference;
typedef std::size_t size_type;
Node() {}
~Node() {}
bool equal_to(const Node& that) {
const box_t& box1 = this->getBox();
const box_t& box2 = that.getBox();
return box1.min_corner().get<0>() == box2.min_corner().get<0>() &&
box1.min_corner().get<1>() == box2.min_corner().get<1>() &&
box1.max_corner().get<0>() == box2.max_corner().get<0>() &&
box1.max_corner().get<1>() == box2.max_corner().get<1>();
}
void setBox(RECT rect) {
box = box_t(point_t(rect.left, rect.top), point_t(rect.right, rect.bottom));
}
const box_t& getBox() const {
return box;
}
protected:
box_t box;
};
NodeTree.h:
#pragma once
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/index/rtree.hpp>
#include "Node.h"
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
namespace boost {
namespace geometry {
namespace index {
class node_indexable {
public:
typedef box_t result_type;
explicit node_indexable() {}
const result_type& operator()(const Node& node) {
return node.getBox();
}
};
template <typename NodeType>
class node_equal_to {
public:
typedef box_t result_type;
explicit node_equal_to() {}
bool equal_to(const NodeType& node1, const NodeType& node2) {
return node1.equal_to(node2);
}
};
} } }
class NodeTree {
public:
typedef Node value;
typedef bgi::linear<16> parameters;
typedef boost::geometry::index::node_indexable indexable_getter;
typedef boost::geometry::index::node_equal_to<Node> equal_to_getter;
bgi::rtree<value, parameters, indexable_getter, equal_to_getter> node_rtree;
NodeTree() {
parameters params;
indexable_getter ind;
equal_to_getter eq;
node_rtree = bgi::rtree<value, parameters, indexable_getter, equal_to_getter> (params, ind, eq);
}
void addNode(Node node) {
node_rtree.insert(node);
}
};
Class with main that triggers the link errors:
// BoostNodeTree.cpp :
//
#include <iostream>
#include "Node.h"
#include "NodeTree.h"
int main()
{
NodeTree nodeTree;
Node node;
RECT rect{ 10, 10, 100, 100 };
node.setBox(rect);
nodeTree.addNode(node);
}

Create a std::vector of type having private constructor

I have a class whose constructors are private. I need to create a std::vector of instances of this class. Now, I am providing my own allocator for this purpose and the class has the allocator as a friend. However on MSVS 2015 with C++11, I get the error as:
error C2664: 'const MyClass*std::_Wrap_alloc<MyClass::MyClassAllocator>::address(const MyClass&) const': cannot convert argument 1 from 'std::_Container_proxy' to 'MyClass&'
Here is my allocator:
struct MyClassAllocator: std::allocator<MyClass>
{
template <class U, class... Args>
void construct(U* ptr, Args&&... args)
{
::new(reinterpret_cast<void*>(ptr)) U(std::forward<Args>(args)...);
}
template <class U> struct rebind { typedef MyClassAllocator other; };
};
This allocator is taken from this SO answer.
Edit:
Here is a MVCE which produces the error in MSVC 2015 with update 3.
#include <vector>
class MyClass
{
friend struct MyClassAllocator;
public:
~MyClass() {}
private:
MyClass() {}
};
struct MyClassAllocator: std::allocator<MyClass>
{
template <class U, class... Args>
void construct(U* ptr, Args&&... args)
{
::new(reinterpret_cast<void*>(ptr)) U(std::forward<Args>(args)...);
}
template <class U> struct rebind { typedef MyClassAllocator other; };
};
int main()
{
std::vector<MyClass, MyClassAllocator> vector;
vector.emplace_back();
}
The error that is produced is:
tests.cpp
1>C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(591): error C2664: 'const MyClass *std::_Wrap_alloc<MyClassAllocator>::address(const MyClass &) const': cannot convert argument 1 from 'std::_Container_proxy' to 'MyClass &'
1> C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(586): note: while compiling class template member function 'void std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>::_Free_proxy(void)'
1> with
1> [
1> _Ty=MyClass,
1> _Alloc=MyClassAllocator
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(559): note: see reference to function template instantiation 'void std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>::_Free_proxy(void)' being compiled
1> with
1> [
1> _Ty=MyClass,
1> _Alloc=MyClassAllocator
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(680): note: see reference to class template instantiation 'std::_Vector_alloc<std::_Vec_base_types<_Ty,_Alloc>>' being compiled
1> with
1> [
1> _Ty=MyClass,
1> _Alloc=MyClassAllocator
1> ]
1> src\tests.cpp(157): note: see reference to class template instantiation 'std::vector<MyClass,MyClassAllocator>' being compiled
What am I doing wrong here?

chained std::bind compile error with VS2015

I'm using VS2015 and I'm playing with std::function and std::bind I found a strange errors.
I have a 2 chained bind operation:
int main()
{
auto func1 = [](int i) -> int {
return i + 1;
};
auto func2 = [](float f, function<int(int)>&& func) -> float {
return f + func(f);
};
auto func2_instance = std::bind(func2, std::placeholders::_1, func1);
cout << func2_instance(0.2) << endl;
auto func3 = [](double d, function<float(float)>&& func)->double {
return d + func(d);
};
//doesn't work
auto func3_instance = std::bind(func3, std::placeholders::_1, std::move(func2_instance));
//works
auto func3_instance = std::bind(func3, std::placeholders::_1, [funcmv = std::move(func2_instance)](float a)->float{
return funcmv(a);
});
func3_instance(0.2);
}
the error I got is related to line func3_instance(0.2)
D:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\type_traits(1468): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
Could you please help? What I miss related to std::bind?
Merci in advance.
If you add code, stolen from here:
Why is there no std::protect?
template<typename T>
struct protect_wrapper : T
{
protect_wrapper(const T& t) : T(t) {}
protect_wrapper(T&& t) : T(std::move(t)) {}
};
template<typename T>
typename std::enable_if< !std::is_bind_expression< typename std::decay<T>::type >::value,
T&& >::type
protect(T&& t)
{
return std::forward<T>(t);
}
template<typename T>
typename std::enable_if< std::is_bind_expression< typename std::decay<T>::type >::value,
protect_wrapper<typename std::decay<T>::type > >::type
protect(T&& t)
{
return protect_wrapper<typename std::decay<T>::type >(std::forward<T>(t));
}
and modify your line to:
auto func3_instance = std::bind(func3, std::placeholders::_1, protect( func2_instance));
the code works ( for me ).

How do I serialize std::chrono::minutes

How do I serialize std::chrono::minutes with cereal or in general?
I tried this
struct A {
std::chrono::minutes m;
template <class Archive>
void serialize(Archive& ar) {
ar(m);
}
};
int main()
{
A a;
std::ostringstream os;
cereal::JSONOutputArchive ar1(os);
ar1(cereal::make_nvp("A", a));
A result;
std::istringstream is(os.str());
cereal::JSONInputArchive ar2(is);
ar2(cereal::make_nvp("A", result));
if (a.m != result.m)
std::cout << "error\n";
}
but get an error in Visual Studio 2015
1> Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these).
1> Serialize functions generally have the following signature:
1>
1> template<class Archive>
1> void serialize(Archive & ar)
1> {
1> ar( member1, member2, member3 );
1> }
1>
1>
1> cereal.hpp(702): note: see reference to function template instantiation 'ArchiveType &cereal::InputArchive<ArchiveType,0>::processImpl<std::chrono::minutes,0>(const T &)' being compiled
1> with
1> [
1> ArchiveType=cereal::JSONInputArchive,
1> T=std::chrono::minutes
1> ]
Ideally I wan to serialize and deserialize in a portable way.
I think I solved the problem by including cereal/types/chrono.hpp
and changing to
#include <cereal/types/chrono.hpp>
class A {
std::chrono::minutes m;
friend class cereal::access;
template <class Archive>
void serialize(Archive& ar)
{
ar(m);
}
};
As you discovered, support for std::chrono::minute, which is really an std::chrono::duration, can be found by including cereal/types/chrono.hpp, which is included with cereal.

Is it possible for C++ to write a template that takes a Container as parameter?

I would try to make my point clear with an example:
We have
template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);
But I'm thinking if it is ok to make it more convenient:
template <typename T> void sort(std::vector<T>& container) {
std::sort( container.begin(), container.end() );
}
template <typename T> void sort(std::list<T>& container);
template <typename T> void sort(std::array<T>& container);
//e.t.c
You know there are many container types, it is possible to code once for all the container types?
void sort(ContainerType<ElementType> &container);
//and container should have begin() and end() methods,
//otherwise the compiler would warn me.
You are talking about concepts in C++. The idea is discussed for a long time for now, but they are still not in the standard. See here:
template<Sortable Cont>
void sort(Cont& container);
The work is close to the end for now, several experimental implementations are already available, and we expect them to hit C++17, hopefully. The nicest thing about concepts is their straightforward error messages:
list<int> lst = ...; // oops, bidirectional iterators
sort(lst); // error: 'T' is not a/an 'Sortable' type
In modern compilers, errors related to templatized code are very confusing. Compare with this example, compiled with Visual Studio 2013:
std::list<int> l;
std::sort(l.begin(), l.end());
// error C2784: 'unknown-type std::operator -(std::move_iterator<_RanIt> &,const std::move_iterator<_RanIt2> &)' : could not deduce template argument for 'std::move_iterator<_RanIt> &' from 'std::_List_iterator<std::_List_val<std::_List_simple_types<int>>>'
// error C2784: 'unknown-type std::operator -(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'std::_List_iterator<std::_List_val<std::_List_simple_types<int>>>'
// error C2784: 'unknown-type std::operator -(const std::_Revranit<_RanIt,_Base> &,const std::_Revranit<_RanIt2,_Base2> &)' : could not deduce template argument for 'const std::_Revranit<_RanIt,_Base> &' from 'std::_List_iterator<std::_List_val<std::_List_simple_types<int>>>'
There is even a tag on SO: c++-concepts.
Its easy to write a sort function that works for any container. Just write:
template<class C>
void sort(C& container) {
std::sort( container.begin(), container.end() );
}
However, if you want your sort function to be picked ONLY for containers, it becomes a little bit more difficult: As concepts are not yet available, you have to write your own type trait for all containers and use SFINAE.
Edit: Come to think of it, as any class with a random access iterator is probably a container anyway, it should be enough to write the following (without the need for a container trait):
#include <type_traits>
template<class C>
typename std::enable_if<std::is_same<typename std::iterator_traits<typename C::iterator>::iterator_category, std::random_access_iterator_tag>{}>::type
sort(C& container) {
std::sort( container.begin(), container.end() );
}
#include <iterator>
#include <utility>
#include <type_traits>
namespace detail
{
using std::begin;
template <typename T, typename = void>
struct has_begin : std::false_type {};
template <typename T>
struct has_begin<T, decltype(void(begin(std::declval<T&>())))> : std::true_type {};
using std::end;
template <typename T, typename = void>
struct has_end : std::false_type {};
template <typename T>
struct has_end<T, decltype(void(end(std::declval<T&>())))> : std::true_type {};
}
template <typename T> using has_begin = detail::has_begin<T>;
template <typename T> using has_end = detail::has_end<T>;
Usage:
template <typename ContainerType>
void sort(ContainerType& container)
{
static_assert(has_begin<ContainerType>{} && has_end<ContainerType>{},
"Invalid container type");
}
Tests:
#include <vector>
#include <list>
namespace X
{
struct A {};
A* begin(A&) { return {}; }
A* end(A&) { return {}; }
}
struct B {};
int main()
{
std::vector<int> v; sort(v); // OK
std::list<int> l; sort(l); // OK
X::A a; sort(a); // OK
int arr[3]{}; sort(arr); // OK
B b; sort(b); // error: Invalid container type
}
DEMO
At the time of answering this question, MikeMB's answer gives the approach but doesn't compile. But here is my attempt. A much lesser complicated approach. You will have to overload SortHelper to accept comparator as well.
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <algorithm>
template<typename C>
void SortHelper(C& container, std::random_access_iterator_tag)
{
std::sort(std::begin(container), std::end(container));
}
template<typename C>
void SortHelper(C& container, std::bidirectional_iterator_tag)
{
container.sort();
}
template<class C>
void sort(C& container)
{
SortHelper(container, typename std::iterator_traits<typename C::iterator>::iterator_category());
}
int main()
{
std::vector<int> ints1 { 3, 2, 1 };
std::list<int> ints2 { 3, 2, 1 };
sort(ints1);
sort(ints2);
std::cout << "printing ints1\n";
for (auto e : ints1 ) { std::cout << e << "\n" ; }
std::cout << "printing ints2\n";
for (auto e : ints2 ) { std::cout << e << "\n" ; }
}
Output
printing ints1
1
2
3
printing ints2
1
2
3

Resources