Creating tuple with allocator c++ - c++

I'm learing tuples in C++ and for now I'm trying to create tuple using allocator from libcxx
template <class _Alloc>
LIBCPP_INLINE_VISIBILITY
tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
for instance:
std::allocator<int> myAllocator;
std::tuple<int> t(std::allocator_arg, myAllocator, 2);
but seems string above called
template <class Alloc>
tuple(allocator_arg_t, const Alloc& a, const Types&...);
what should I change for this?
As well, there is one row that isn't clear for me:
explicit
tuple(_Up&&... __u)
how does this call?

When you look into your implementation's source and see
namespace std {
// Other things
template <typename ... _Tp>
class tuple {
// More things
template <class _Alloc>
LIBCPP_INLINE_VISIBILITY
tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
// an implementation of this constructor
};
}
That is the constructor that cppreference names
template <class Alloc>
tuple(allocator_arg_t, const Alloc& a, const Types&...);
Your implementation has chosen to use names that are reserved for its use. What exactly those names are doesn't matter to the compiler.
what const _Tp& ... __t is?
It's a parameter pack of elements to copy into the tuple. For std::tuple<int>, it is const int&, for std::tuple<std::string, bool, char> it is const std::string &, const bool &, const char &. __t is the name of the parameter pack. C++ allows templates to have different numbers of parameters.
what about tuple(_Up&&... __u)?
That's overload (3)
Converting constructor. Initializes each element of the tuple with the corresponding value in std::forward<UTypes>(args).
This overload only participates in overload resolution if sizeof...(Types) == sizeof...(UTypes) and sizeof...(Types) >= 1 and std::is_constructible<Ti, Ui&&>::value is true for all i.
The constructor is explicit if and only if std::is_convertible<Ui&&, Ti>::value is false for at least one i.
E.g. for std::tuple<int> tup('a');, tup would be initialised by matching UTypes... with char, and the first member would have the numeric value of 'a' (97 on most platforms).
Note that there isn't much point in using an allocator-aware constructor for std::tuple<int>, because int is not a allocator-aware type. Those constructors exist for cases like
using statefully_allocated = std::vector<int, my_stateful_allocator<int>>;
my_stateful_allocator<int> alloc1 = /* something */
statefully_allocated source(alloc);
my_stateful_allocator<int> alloc2 = /* something else */
std::tuple<statefully_allocated, char> tup(std::allocator_arg, alloc2, source, 'a');
Where the statefully_allocated member copies the contents of source, but uses a copy of alloc2 to allocate. the char member is just an ordinary char, alloc2 plays no part in it's construction. See Uses-allocator construction

Related

no matching member function for call to 'insert'

I have the following method declaration on a basic_buffer class:
const_iterator insert(const_iterator position, typename argument<value_type>::type val)
Notice the type of the second argument. I often use this argument traits that basically decides whether the argument should be passed by copy or by reference when receiving template arguments. In this case, value_type is a typedef of the template argument T. For instance, fundamental types should be passed by copy instead of const reference. Here's the implementation:
template <typename T> struct argument
{
typedef std::conditional<std::is_fundamental<T>::value || std::is_pointer<T>::value, const T, const T &> type;
};
Notice how fundamental and pointer types evaluate to const T and other types evaluate to const T &. This has been working great so far.
Now consider the following function:
template <class T>
void foo()
{
typedef basic_buffer<T> _storage_type;
typedef typename _storage_type::value_type _value_type;
_value_type value = 0;
_storage_type _storage;
_storage.insert(_storage.end(), value);
}
Several details are omitted. This is what I get:
error: no matching member function for call to 'insert'
_storage.insert(_storage.end(), value);
~~~~~~~~~^~~~~~
What surprises me is this overload version not being matched:
note: candidate function not viable: no known conversion from '_value_type' (aka 'unsigned char') to 'typename argument<value_type>::type' (aka 'conditional<std::is_fundamental<unsigned
char>::value || std::is_pointer<unsigned char>::value, const unsigned char, const unsigned char &>') for 2nd argument
const_iterator insert(const_iterator position, typename argument<value_type>::type val)
To make matters even more confusing, if I cast value to _value_type (that, notably, is already its type) it works:
_storage.insert(_storage.end(), static_cast<_value_type>(value));
So I can solve this by casting value, but rather not. What is happening here?
You have
typedef std::conditional<std::is_fundamental<T>::value || std::is_pointer<T>::value, const T, const T &> type;
So type is a std::conditional<std::is_fundamental<T>::value || std::is_pointer<T>::value, const T, const T &>
When you call
_storage.insert(_storage.end(), value);
It is trying to convert value to a std::conditional<std::is_fundamental<T>::value || std::is_pointer<T>::value, const T, const T &>
You need to add ::type to the conditional to get the resulting type from the condition.
typedef std::conditional<std::is_fundamental<T>::value || std::is_pointer<T>::value, const T, const T &>::type type;

forward_list: assign(_InputIterator __first, _InputIterator __last) / assign(size_type __n, const _Tp& __val)

I have implemented a subset of the forward_list and wanted to test the method assign(size_type __n, const _Tp& __val) but I get a compiler error because the compiler wants to call the method assign(_InputIterator __first, _InputIterator __last) instead.
I have written the following snippet, just to illustrate the problem:
test.h
#ifndef TEST_H
#define TEST_H
#include <utility> // Just to get the std::size_t
template<typename _Tp>
class forward_list {
public:
typedef std::size_t size_type;
void assign(size_type n, const _Tp& val)
{
printf("%s\n", __PRETTY_FUNCTION__);
}
template<typename _InputIterator>
void assign(_InputIterator first, _InputIterator last)
{
printf("%s\n", __PRETTY_FUNCTION__);
}
};
#endif // TEST_H
test.cpp
#include <stdlib.h>
#include <stdio.h>
#include "test.h"
int main()
{
forward_list<int> l;
l.assign(10, 5);
return 0;
}
The output of the execution is:
void forward_list<_Tp>::assign(_InputIterator, _InputIterator) [with _InputIterator = int; _Tp = int]
I would like to have the method assign(size_type __n, const _Tp& __val) called.
Compiler version (just in case it matters): g++ (Debian 4.7.2-5) 4.7.2
I have used similar signatures to the signatures used in the std::forward_list and, with the following code snippet (using the STL):
std::forward_list<int> l;
l.assign(10, 5);
The compiler knows that it has to call assign(size_type __n, const _Tp& __val) and doesn't get confused. What am I missing?
When you call l.assign(10, 5);, there are two viable overloads:
void assign(size_type n, const int& val)
template <>
void assign(int first, int last)
When we say that non-template functions are preferred to template functions, that is only true if the two have indistinguishable conversion sequences. But in this case, the function template will match exactly (both of your arguments are int, no conversion necessary), while the non-template will have to undergo promotation (have to promote 10 from int to size_t). So that's why the function template overload is preferred.
As to how to fix it, you just need to make the template not a viable overload. That involves writing a type_trait for input iterator, which using void_t is not hard:
template <typename... >
using void_t = void;
template <typename T, typename = void>
struct is_input_iterator : std::false_type { };
template <typename T>
struct is_input_iterator<T, void_t<
decltype(std::declval<T>() == std::declval<T>()),
decltype(std::declval<T>() != std::declval<T>()),
decltype(*std::declval<T>()),
decltype(++std::declval<T>()),
decltype(std::declval<T>()++)
>> : std::true_type { };
And then require is_input_iterator:
template <typename _InputIterator,
typename = std::enable_if_t<is_input_iterator<_InputIterator>::value>>
void assign(_InputIterator first, _InputIterator last);
There are lots of other ways to do this sort of thing, I just happen to like void_t. Regardless of which way you do it, you have to ensure that the template simply isn't viable.
The assign overload that you want to be called takes an unsigned integral type as the first argument, but you're passing it two signed integers. If you change the call to
l.assign(10U, 5); // make the first argument unsigned
the first assign overload is called. But clearly, this is not the right solution to your problem in general.
You need to constrain the assign template so that it is only viable when the type of the arguments satisfy requirements for iterators. One way to do this is to inspect iterator_traits for the type involved. If the iterator_category satisfies the requirements of an InputIterator, then the function template can be used.
template<typename InputIterator>
typename std::enable_if<
std::is_base_of<std::input_iterator_tag,
typename std::iterator_traits<InputIterator>::iterator_category
>::value
>::type
assign(InputIterator first, InputIterator last)
{
printf("%s\n", __PRETTY_FUNCTION__);
}
Live demo
Note that technically the above solution isn't guaranteed to work before C++17 (or whatever it'll be called) because iterator_traits isn't required to be SFINAE friendly until then, and it could result in a hard error instead of substitution failure. But chances are your implementation's iterator_traits is already SFINAE friendly, and you won't run into any issues.
size_t isn't guaranteed to be included by <utility>, use one of the headers listed on the linked page.
Don't use identifiers that begin with an underscore and are followed by an uppercase characters, those are reserved for the implementation.

std::make_pair type deduction

I came across some odd thing I would like to have an explanation for. The following code snippet provides a simple class template type and two operator<<s: one for specializations of type and one for a std::pair of type specializations.
#include <ostream>
#include <utility>
template <typename T>
class type {
public:
T value_;
};
template <typename CTy, typename CTr, typename T>
std::basic_ostream<CTy,CTr>&
operator<<(std::basic_ostream<CTy,CTr>& os, type<T> const& a)
{
return os << a.value_;
}
template <typename CTy, typename CTr, typename T>
std::basic_ostream<CTy,CTr>&
operator<<(std::basic_ostream<CTy,CTr>& os, std::pair<T const, T const> const& a)
{
return os << a.first << ',' << a.second;
}
#include <iostream>
int
main()
{
using float_type = type<float>;
float_type const a = { 3.14159 };
float_type const b = { 2.71828 };
#if 0
std::cout << std::make_pair(a, b)
<< std::endl;
#else
std::cout << std::pair<float_type const, float_type const>(a, b)
<< std::endl;
#endif
}
The main function provides a specialization and two variables of that specialization. There are two variants for displaying the variables as a std::pair. The first fails because std::make_pair seems to strip the const specifier from the variables, which in turn doesn't match with the signature of the second operator<<: std::pair<T const, T const>. However, constructing a std::pair specialization (second std::cout line in main) works as well as removing the const specification for T from operator<< for std::pair, i.e. std::pair<T, T>.
Compiler messages::
gcc 4.9.2
std_make_pair.cpp: In function 'int main()':
std_make_pair.cpp:52:35: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
std::cout << std::make_pair(a, b) << std::endl;
^
In file included from std_make_pair.cpp:3:0:
/usr/include/c++/4.9.2/ostream:602:5: note: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::pair<type<float>, type<float> >]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
clang 3.5 (non-viable functions from system headers removed)
std_make_pair.cpp:52:13: error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>')
and 'pair<typename __decay_and_strip<const type<float> &>::__type, typename __decay_and_strip<const
type<float> &>::__type>')
std::cout << std::make_pair(a, b) << std::endl;
~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
std_make_pair.cpp:30:1: note: candidate template ignored: can't deduce a type for 'T' which would make
'const T' equal 'type<float>'
operator<<(std::basic_ostream<CTy,CTr>& os, std::pair<T const, T const> const& a)
so, here's the question: am I supposed to specify an operator<< taking a std::pair of T instead of T const? Isn't that watering down the contract I'm setting up with any user of the functionality, i.e. with T const I basically promise to use T only in non-mutating ways?
The first fails because std::make_pair seems to strip the const specifier from the variables, which in turn doesn't match with the signature of the second operator<<: std::pair<T const, T const>
That is correct. make_pair is a function template that relies on std::decay to explicitly drop const, volatile, and & qualifiers:
template <class T1, class T2>
constexpr pair<V1, V2> make_pair(T1&& x, T2&& y);
Returns: pair<V1, V2>(std::forward<T1>(x), std::forward<T2>(y));
where V1 and V2 are determined as follows: Let Ui be decay_t<Ti> for each Ti. Then each Vi is X& if Ui equals reference_wrapper<X>, otherwise Vi is Ui.
The compiler is completely correct to reject your code - you added a stream operator for pair<const T, const T>, but are trying to stream a pair<T, T>. The solution is to just remove the extra const requirement in your stream operator. Nothing in that function requires that the pair consist of const types - just that the types themselves are streamable, which is independent of their constness. There is nothing wrong with this:
template <typename CTy, typename CTr, typename T>
std::basic_ostream<CTy,CTr>&
operator<<(std::basic_ostream<CTy,CTr>& os, std::pair<T, T> const& a)
{
return os << a.first << ',' << a.second;
}
You're already taking the pair by reference-to-const, it's not like you can modify its contents anyway.

How do you use vector as a base class

Win7
Cygwin
This the first time I've used templates & containers. I don't understand the errors. To my (naive) way of looking at things, I have defined an allocator (_Alloc) and a typdef (allocator_Type). The messages appear to be saying that I haven't done my homework properly. I have no clue as to what to do.
The code is:
template<typename T, typename _Alloc = std::allocator<T>>
class Array : public vector<T, _Alloc> {
public:
typedef T value_type;
typedef _Alloc allocator_Type;
private:
int compar (const void* p1, const void* p2) { T v1 = (T)*p1;
T v2 = (T)*p2;
return (v1 < v2)? -1: (v1 > v2)? 1: 0; }
public:
explicit Array (const allocator_Type& alloc = allocator_type()) : vector<T, _Alloc>(alloc) { };
explicit Array (size_t n) : vector<T, _Alloc>(n) { };
Array (size_t n, const T& val,
const allocator_type& alloc = allocator_type()): vector<T, _Alloc>(n, val, alloc) { };
};
The error messsages are:
main.cpp:31:27: error: 'allocator_type' does not name a type
const allocator_type& alloc = allocator_type()): vector<T, _Alloc>(n, val, alloc) { };
^
main.cpp:31:27: note: (perhaps 'typename std::vector<_Tp, _Alloc>::allocator_type' was intended)
main.cpp:31:66: warning: ISO C++ forbids declaration of 'alloc' with no type [-fpermissive]
const allocator_type& alloc = allocator_type()): vector<T, _Alloc>(n, val, alloc) { };
^
main.cpp:28:65: warning: there are no arguments to 'allocator_type' that depend on a template parameter, so a declaration of 'allocator_type' must be available [-fpermissive]
explicit Array (const allocator_Type& alloc = allocator_type()) : vector<T, _Alloc>(alloc) { };
^
main.cpp:31:66: warning: there are no arguments to 'allocator_type' that depend on a template parameter, so a declaration of 'allocator_type' must be available [-fpermissive]
const allocator_type& alloc = allocator_type()): vector<T, _Alloc>(n, val, alloc) { };
^
This has been stated in comments but not posted as an answer yet: you don't.
The standard library containers are not supposed to be used as (public) base classes. They are non-polymorphic, so you can't pass an object derived from one safely to any function which expects a pointer or reference to the container.
You could , in theory, use a standard container as private base class. This has the same semantics as a private member variable, but it would make your code a lot easier to follow for others if you just used a private member variable.
First - you have a typo: uppercase T in allocator_Type and lowercase in const allocator_Type& alloc = allocator_type(). Second - std::vector destructor is not virtual, hence you really should not derive from it unless you never cast and delete via base class.

How does make_pair know the types of its args?

The definition for make_pair in the MSVC++ "utility" header is:
template<class _Ty1,
class _Ty2> inline
pair<_Ty1, _Ty2> make_pair(_Ty1 _Val1, _Ty2 _Val2)
{ // return pair composed from arguments
return (pair<_Ty1, _Ty2>(_Val1, _Val2));
}
I use make_pair all the time though without putting the argument types in angle brackets:
map<string,int> theMap ;
theMap.insert( make_pair( "string", 5 ) ) ;
Shouldn't I have to tell make_pair that the first argument is std::string and not char* ?
How does it know?
Function template calls can usually avoid explicit template arguments (ie make_pair<…>) by argument deduction, which is defined by C++03 §14.8.2. Excerpt:
When a function template
specialization is referenced, all of
the template arguments must have
values. The values can be either
explicitly specified or, in some
cases, deduced from the use.
The specific rules are a bit complicated, but typically it "just works" as long as you have only one specialization which is generally qualified enough.
Your example uses two steps of deduction and one implicit conversion.
make_pair returns a pair<char const*, int>,
then template<class U, classV> pair<string,int>::pair( pair<U,V> const & ) kicks in with U = char*, V = int and performs member-wise initialization,
invoking string::string(char*).
It doesn't. make_pair generated a pair<char*,int> (or maybe a pair<char const*,int>).
However, if you'll note in the implementation of pair there's a templated copy constructor:
template < typename Other1, typename Other2 >
pair(pair<Other1,Other2>& other)
: first(other.first), second(other.second)
{}
This may be implemented in slightly different ways but amounts to the same thing. Since this constructor is implicit, the compiler attempts to create pair<std::string,int> out of your pair<char*,int> - since the necessary types are convertible this works.
make_pair() exists precisely so that argument type deduction can be used to determine the template parameter types.
See this SO question: Using free function as pseudo-constructors to exploit template parameter deduction
It relies on the fact that the constructor of std::string accepts a const char*.
It doesn't matter if this constructor of std::string is explicit or not. The template deducts the type and uses the copy constructor of pair to convert it. It also doesn't matter whether or not the pair constructor is explicit.
If you turn the constructor of std::string into:
class string
{
public:
string(char* s)
{
}
};
you get this error:
/usr/include/c++/4.3/bits/stl_pair.h: In constructor ‘std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = const char*, _U2 = int, _T1 = const string, _T2 = int]’:
foo.cpp:27: instantiated from here
/usr/include/c++/4.3/bits/stl_pair.h:106: error: invalid conversion from ‘const char* const’ to ‘char*’
/usr/include/c++/4.3/bits/stl_pair.h:106: error: initializing argument 1 of ‘string::string(char*)’
The constructor looks like this:
template<class _U1, class _U2>
pair(const pair<_U1, _U2>& __p)
: first(__p.first),
second(__p.second) { }
The copy constructor looks like this:
template<class _U1, class _U2>
pair(const pair<_U1, _U2>& __p)
: first(__p.first),
second(__p.second) { }