Incompatibility between std::swap boost::unordered_set and std::vector? - c++

something in is messing out with std::swap and boost::unordered_set ?
I am experiencing some problems while using std::swap and boost::unordered_set. The following code generates a C2039 error on VC2017/VC2019. Comment the line #include and it works finely. Does someone has any clue about this problem ?
#include <vector>
#include <boost/unordered/unordered_set.hpp>
typedef boost::unordered_set<size_t> index_list_type;
int main()
{
index_list_type toto;
index_list_type tutu;
std::swap<index_list_type>(toto, tutu);
return 0;
}
MSVC\14.20.27508\include\vector(1702): error C2039: '_Alloc' : is not member of 'boost::unordered::unordered_set,std::equal_to,std::allocator>'

You should just use std::unordered_set, no need for boost.
Boost doesn't have to work with std algorithms. Check here expecially the "all standard containers specialize it in such a way that only a few internal pointers are swapped instead of their entire contents, making them operate in constant time." part.
Sure many things might be cross compatible between boost and std, but if all the tools you need are available in the same namespace, just use that one.

Boost is an entire ecosystem in itself, aimed at minimizing the reliance on the C++ standard library (remember that std::swap is available since C++11 only). As such, there is boost::swap(), which has overloads for all Boost data types, including boost::unordered_set:
// swap
template<typename Value, typename Hash, typename Pred, typename Alloc>
void swap(unordered_set<Value, Hash, Pred, Alloc>&,
unordered_set<Value, Hash, Pred, Alloc>&);
If you use std::swap then you should consider std::unordered_set, and vice versa if you can't or don't want to, then you should stick with Boost all the way. Try to minimize mixing std and boost.
As to the error - this looks like is a bug in the MSVC standard library; the std::swap<vector> implementation is not explicitly restricted to vectors, which is wrong since it fails whenever the type is specified explicitly.
It looks roughly like this:
template<class T>
class _Vb_reference
{
using _Alvbase = typename T::_Alloc;
};
template<class T>
void swap(_Vb_reference<T> _Left, _Vb_reference<T> _Right)
{
}
That only works when the arguments are deduced, as in
std::swap(toto, tutu); // _Vb_reference<T> is non-deduced context
But fails when the type is specified explicitly:
std::swap<index_list_type>(toto, tutu); // instantiation of _Vb_reference<index_list_type> fails = hard error
A better implementation would include some SFINAE to restrict the template to _Vb_reference<T> types.

Related

Why alias a template parameter in C++ standard containers?

Reviewing the code of Microsoft's STL (specifically std::vector), I came across the following lines of code (irrelevant code replaced with /* ... */):
// CLASS TEMPLATE vector
template <class _Ty, class _Alloc = allocator<_Ty>>
class vector // varying size array of values
{
/* ... */
public:
/* ... */
using value_type = _Ty;
using allocator_type = _Alloc;
using pointer = typename _Alty_traits::pointer;
using const_pointer = typename _Alty_traits::const_pointer;
using reference = _Ty&;
using const_reference = const _Ty&;
using size_type = typename _Alty_traits::size_type;
using difference_type = typename _Alty_traits::difference_type;
/* ... */
};
I was wondering why the convention of assigning a type alias to a template type is used here?
I was wondering why the convention of assigning a type alias to a template type is used here?
Suppose you have a template function that accept an STL container (std::vector, std::deque, std::set, std::multi_set, ...)
template <typename T>
void foo (T const & t)
{
// ...
}
and that you need the type of contained values.
You can, inside foo(), simply write
using needed_type = typename T::value_type;
and this works for std::vector, std::deque, std::set, std::multi_set, std::array, std::map, std::multi_map, etc.
I was wondering why the convention of assigning a type alias to a
template type is used here?
Because it is
the standard way of doing,
makes less error-prone code,
less typing,
more readable, and
all the above makes life easy!
For instance, let's consider the const_pointer, public template alias of std::vector
using const_pointer = typename _Alty_traits::const_pointer;
At some point, you want to know this type and use in a function, how could have been possible without the above alias?
Of course, you can write
#include <memory> // std::allocator_traits
using const_pointer = typename std::allocator_traits<typename std::vector</*type*/>::allocator_type>::const_pointer;
anywhere in your program. But that tends to more error-prone situations (e.g. missing some typenames and so on), and more typing.
Therefore, it makes sense to collect those kinds of types of a container and provide public-aliases-types.
The C++ standard requires std::vector to provide a double-handful of nested names, and those are the ones the question is asking about. That's why value_type, allocator_type, pointer, etc. are there. You can use those names in your code when you need the types that they refer to. It's not at all uncommon to see, for example, std::vector<int>::iterator in user code to refer to the type of the iterator that std::vector<int> provides.
As to why they're written the way they are, that's a broader consistency issue. Templates throughout the Dinkumware implementation of the C++ standard library (which is what Microsoft ships) use _Ty as the base name for general types. When there are two types you'll see _Ty1 and _Ty2. When there's an internal typedef for a name it will be _Myty (for "My" type). That consistency makes maintaining the code easier.
That convention actually used for providing "traits". Naming for those types follows some convention that allows write functions like distance in terms of those traits and make it working for many containers.
And I'm pretty sure that having those types for standard C++ library is part of specification and they had to adhere it.

Metafunction to test whether object is compatible with boost range

Is there, or how would you write, a metafunction class that tests whether a class is compatible with boost::range? I want to use the boost::enable idiom, something like
template <typename T>
Constructor::Constructor(const T& t, __attribute__((unused)) typename boost::enable_if<is_range_compatible<T> >::type* aux=NULL)
for an appropriate is_range_compatible metafunction. I know about is_container from pretty_print, which captures a lot of cases, but not everything that works with boost::range.
Edit This is using C++03, so I don't have access to C++11 features. I'm using an old, gcc 4.1, and boost 1.51.
Do you mean enable_if?
If you can persuade the Boost concept checks to work usefully with it (instead of the macro + compile error it uses now), checks like ForwardConceptRange are already provided.
Otherwise, is it a problem to use the existing BOOST_CONCEPT_ASSERT macro instead?
If you upgrade to Boost 1.54, there is a nice library called TTI. It allows you to compose type traits introspection meta functions at will, so that you can easily spin off you own meta predicates which can be used to enable or disable function templates. Though it is a nice meta programming exercise, I don't recommend to do that in production code. I found it hard to catch the "false negatives" which arise from implementation details of STL containers. For example, the associative containers coming with MSVC11 inherit their begin and end member functions from a base class which yields false negative with meta predicates generated via BOOST_TTI_HAS_MEMBER_FUNCTION. Despite of his nickname, Useless gave you a good advice: Use concepts coming with Boost.Range to reject or accept the type inside the body of the function template such as the constructor in your example... Of course, this will not solve the convertibility problem for your Constructor...
EDIT: example, taken from vex:
#include <boost/tti/has_member_function.hpp>
#include <vector>
#include <map>
namespace tti_test {
BOOST_TTI_HAS_MEMBER_FUNCTION(begin);
// .. begin test class for mstest
// this succeeds in both variants
TEST_METHOD(has_const_member_function_begin_is_true_for_vector)
{
Assert::IsTrue(has_member_function_begin<
std::vector<int>::const_iterator (std::vector<int>::*)() const
>::value);
Assert::IsTrue(has_member_function_begin<
const std::vector<int>, std::vector<int>::const_iterator
>::value);
}
// this fails in both variants...
TEST_METHOD(has_const_member_function_begin_is_true_for_map)
{
Assert::IsTrue(has_member_function_begin<
std::map<int, int>::const_iterator (std::map<int, int>::*)() const
>::value);
Assert::IsTrue(has_member_function_begin<
const std::map<int, int>, std::map<int, int>::const_iterator
>::value);
}
// end test class for mstest
}

Returning an anonymous tr1 array initialized with boost.assign

Ok, this works on my compiler (vs2008) but I'm trying to figure out if I'm doing something non-standard. Here's a trivial example what I'm doing:
std::tr1::array<int, 3> OneTwoThree() {
return boost::assign::list_of(1)(2)(3).to_array(std::tr1::array<int, 3>());
}
I'm cheating around the fact that the to_array adapter doesn't actually use the argument you pass into it, it's just using it to figure out the type. The examples, however, show it being used more like this:
std::tr1::array<int, 3> a = boost::assign::list_of(1)(2)(3).to_array(a);
Any ideas on whether or not just throwing a value-initialized array into to_array it is kosher? Is there a cleaner way to do this?
The to_... member functions all take an argument solely for the purpose of assisting with template argument deduction, so yes, passing a value-initialized† instance of the same type you want as the return type is safe, though needlessly inefficient.
However, the to_... member functions only exist to assist broken compilers that don't properly support templated conversion operators -- why are you using them in the first place? The clean syntax would be simply:
boost::array<int, 3> OneTwoThree() {
return boost::assign::list_of(1)(2)(3);
}
Note that I've used boost::array<> here rather than std::tr1::array<>; the reason is that the Boost.Assign library has no knowledge (yet) of TR1/C++11 standard libraries, and thus is not properly specialized for std::array<> or std::tr1::array<>. To add this specialization yourself, and consequently make the above code work with std::tr1::array<>, add the following code after including the Boost.Assign headers:
namespace boost { namespace assign_detail {
template<typename T, std::size_t sz>
type_traits::yes_type assign_is_array(std::tr1::array<T, sz> const*);
}}
(Note: only tested with Boost 1.48; earlier versions may need a different specialization.)
† The syntax in your question is not default-construction, it's value-initialization.

Is there a type-trait to remove top-level cv and reference at once?

I just want to know if there is already one provided by the standard. I know it's easy to make one yourself
// for C++03, use <tr1/type_traits> and std::tr1
#include <type_traits>
template<class T>
struct remove_toplevel{
typedef typename std::remove_reference<T>::type noref_T;
typedef typename std::remove_cv<noref_T>::type noref_nocv_T;
typedef noref_nocv_T type;
};
but I think I forgot something in there or got the order wrong, so it'd be nice to have a prepared one, if one exists.
std::decay, I believe, performs this functionality.
I prefer combining the two functionalities since it describes exactly what the intention is:
C++11 std::remove_cv<std::remove_reference<T>::type>::type
C++14 std::remove_cv_t<std::remove_reference_t<T>>
C++20 std::remove_cvref_t<T>

Wrapper contains() function for different containers

Inspired by contains(), I want do declare contains(), fitting misc containers.
// for std::vector, std::list, .. (1)
template<typename C, typename T>
bool contains(const C& container, const T& val)
{
return ::std::find(container.begin(), container.end(), val) != container.end();
}
// partial specialization for std::map (2)
template<typename K, typename V>
bool contains(const ::std::map<K, V>& container, const K& key)
{
// std::map.find() is better than std::find used in (1)
return container.find(key) != container.end();
}
Following question, I want to add the functions to namespace the arguments belongs too.
Questions:
Types of val from (1) and key from (2) are unknown. Does it mean I don't need to put the functions to any namespace or do I need to put them in std namespace, the containers belong to?
Is it possible to improve (2) it will preferred by compiler than (1) for std::map, std::set, boost::unordered_map, boost::unordered_set?
boost::algorithm::contains(). Do I need choose another name for my wrapper?
(1) Don't add anything to the std namespace
(2) As Space_C0wb0y points out, (2) is not a partial specialization, but an overload. I'm not sure if this is standard behaviour, but on VS2008 this is resolved correctly (the overloaded version is used for map). In either case, I think a slighly better version would be:
template<typename C>
bool contains(const C & mapContainer, const typename C::key_type & key)
{
// std::map.find() is better than std::find used in (1)
return mapContainer.find(key) != mapContainer.end();
}
This is a partial specialization (T is specialized to C::key_type) and would work for all types that has the key_type typedef (e.g. std::map, boost::unordered_map etc.)
(3) Put in separate namespace (see #Tony's answer)
Sidenote: I'm not sure I think these functions should have the same name. If I saw a function contains() accepting a map + another argument I could think that (1) the function checks if the map contains an entry for the given value (e.g. some key has the value provided) or (2) the function checks if there is such an entry in the map (e.g. the provided value is a pair). Instead I would call the function contains_key() for maps.
Edit:
After a bit of checking I suspect that the code above isn't compliant as it uses "template typedefs". This is not a standard C++ feature, but it seems that Visual Studio supports it in some cases. There's probably a workaround for this, but not one I'm clever enough to come up with now.
On number 3. you should place your version of contains in it's own namespace to avoid naming clashes. That's the purpose of namespaces.
Yes, keep them in a separate namespace.
The only thing to place in the same namespace as the argument type is operator overloads, to allow for Koenig (argument-dependent) lookup. These are not overloaded operators. End of story.
Note how this also answer question 2.: how you make the compiler prefer your implementations:
using myownversions::contains;
(assuming you named your namespace myownversions for now)
You must not put them into the std namespace. This is forbidden. You can put them into any namespace you like.
There is probably some SFINAE-magic you can do there, but I cannot come up with it in my own.
See #Tony's answer.