C++ source code compilation error in MinGW with std::copy function - c++

I'm trying to compile the following C++ code and getting some errors. Am I missing some libraries? I'm using MinGW on Windows 7 64 bit.
//ch 18
#include <algorithm>
class vector{
int sz;
double* elem;
public:
vector(const vector&);
};
vector:: vector(const vector& arg)
:sz{arg.sz}, elem{new double[arg.sz]}
{
std::copy(arg,arg.sz,elem);
}
Here is the error messages.
$ g++ ch18copy.cpp -std=c++11 -o ch18copy
ch18copy.cpp: In copy constructor 'vector::vector(const vector&)':
ch18copy.cpp:15:28: error: no matching function for call to 'copy(const vector&,
const int&, double*&)'
std::copy(arg,arg.sz,elem);
^
ch18copy.cpp:15:28: note: candidate is:
In file included from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\algorithm:61:0,
from ch18copy.cpp:3:
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_algobase.h:450:5: note: temp
late<class _II, class _OI> _OI std::copy(_II, _II, _OI)
copy(_II __first, _II __last, _OI __result)
^
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_algobase.h:450:5: note: te
mplate argument deduction/substitution failed:
ch18copy.cpp:15:28: note: deduced conflicting types for parameter '_II' ('vect
or' and 'int')
std::copy(arg,arg.sz,elem);
^

It looks like you aren't using the right parameters for std::copy.
From http://www.cplusplus.com/reference/algorithm/copy/:
template <class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result);
From their example:
int myints[]={10,20,30,40,50,60,70};
std::vector<int> myvector (7);
std::copy ( myints, myints+7, myvector.begin() );
So the first two parameters are the start and end of the range you want to copy, and the third parameter is where you want to copy to.
In your case, this would look something like this (disclaimer: didn't test this):
std::copy(arg.elem, arg.elem + arg.sz, elem);

Related

c++98 use iterator constructor only if InputIt is an iterator of type T

For a school project I have to implement std::vector but only using C++98 standard.
The problem is that the size constructor and iterator constructor are conflicting with each other when I call it with a signed integer, so I came up with this ( whith my own implementations of enable_if, is_same, and iterator_traits):
// Size constructor
explicit vector(
size_type count,
const T &value = T(),
const Allocator &alloc = Allocator()
) : _allocator(alloc),
_capacity(count),
_size(count),
_array(_allocator.allocate(_capacity)) {
std::fill(begin(), end(), value);
}
// Iterator constructor
template <
class InputIt
> vector(
InputIt first, InputIt last,
const Allocator &alloc = Allocator(),
typename ft::enable_if< ft::is_same< typename ft::iterator_traits< InputIt >::value_type, T >::value, int >::type = 0
) : _allocator(alloc),
_capacity(std::distance(first, last)),
_size(_capacity),
_array(_allocator.allocate(_capacity)) {
std::copy(first, last, begin());
}
But now I have a problem with my implementation of iterator_traits: when I call it with an int of course it doesn't work because int doesn't have iterator member types, but when I look at cppreference about iterator_traits, it says that If Iter does not have all five member types difference_type, value_type, pointer, reference, and iterator_category, then this template has no members by any of those names (std::iterator_traits is SFINAE-friendly) (since C++17) (until C++20) which means that the check isn't implemented before C++17, so how does the real std::vector check for Iterator validity even before C++11?
Here is the compiler error I get when calling the constructor with 2 ints:
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:22:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::difference_type difference_type;
^
/home/crochu/Documents/42/ft_containers/vector.hpp:78:55: note: in instantiation of template class 'ft::iterator_traits<int>' requested here
typename ft::enable_if< ft::is_same< typename ft::iterator_traits< InputIt >::value_type, T >::value, int >::type = 0
^
/home/crochu/Documents/42/ft_containers/main.cpp:19:20: note: while substituting deduced template arguments into function template 'vector' [with InputIt = int]
ft::vector< int > v(5, 42);
^
In file included from /home/crochu/Documents/42/ft_containers/main.cpp:13:
In file included from /home/crochu/Documents/42/ft_containers/ft_containers.hpp:15:
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:23:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::value_type value_type;
^
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:24:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::pointer pointer;
^
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:25:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::reference reference;
^
/home/crochu/Documents/42/ft_containers/iterator_traits.hpp:26:20: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename Iter::iterator_category iterator_category;
^
5 errors generated.
As an example, the implementation of this constructor in libstdc++ is located in the header bits/stl_vector.h:
template<typename _InputIterator>
vector(_InputIterator __first, _InputIterator __last,
const allocator_type& __a = allocator_type())
: _Base(__a)
{
// Check whether it's an integral type. If so, it's not an iterator.
typedef typename std::__is_integer<_InputIterator>::__type _Integral;
_M_initialize_dispatch(__first, __last, _Integral());
}
This is a tag dispatch using a proto-std::integral_constant class, to one of these functions:
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 438. Ambiguity in the "do the right thing" clause
template<typename _Integer>
void
_M_initialize_dispatch(_Integer __n, _Integer __value, __true_type)
{
this->_M_impl._M_start = _M_allocate(_S_check_init_len(
static_cast<size_type>(__n), _M_get_Tp_allocator()));
this->_M_impl._M_end_of_storage =
this->_M_impl._M_start + static_cast<size_type>(__n);
_M_fill_initialize(static_cast<size_type>(__n), __value);
}
// Called by the range constructor to implement [23.1.1]/9
template<typename _InputIterator>
void
_M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
__false_type)
{
_M_range_initialize(__first, __last,
std::__iterator_category(__first));
}
I'd say that's about as elegant as you could get under your constraints!

RcppParallel no matching function for call to 'transform'

I have a package posted on CRAN which uses multiple cores through the RcppParallel framework. It has the problem being installed on r-devel-linux-x86_64-fedora-clang and r-patched-solaris-x86. I get the following error messages (there are couple of similar messages related to std::transform so I present just one of them for brevity):
1.For the r-patched-solaris-x86:
ParallelFunctions.cpp: In member function ‘virtual void ParallelVectorExpStruct::operator()(std::size_t, std::size_t)’:
ParallelFunctions.cpp:134:27: error: no matching function for call to ‘transform(RcppParallel::RVector<double>::const_iterator, RcppParallel::RVector<double>::const_iterator, RcppParallel::RVector<double>::iterator, <unresolved overloaded function type>)’
::exp);
^
In file included from /opt/csw/include/c++/5.2.0/algorithm:62:0,
from /home/ripley/R/Lib32/Rcpp/include/RcppCommon.h:63,
from /home/ripley/R/Lib32/RcppArmadillo/include/RcppArmadilloForward.h:26,
from /home/ripley/R/Lib32/RcppArmadillo/include/RcppArmadillo.h:31,
from ParallelFunctions.h:4,
from ParallelFunctions.cpp:1:
/opt/csw/include/c++/5.2.0/bits/stl_algo.h:4164:5: note: candidate: template<class _IIter, class _OIter, class _UnaryOperation> _OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation)
transform(_InputIterator __first, _InputIterator __last,
^
/opt/csw/include/c++/5.2.0/bits/stl_algo.h:4164:5: note: template argument deduction/substitution failed:
ParallelFunctions.cpp:134:27: note: couldn't deduce template parameter ‘_UnaryOperation’
::exp);
^
In file included from /opt/csw/include/c++/5.2.0/algorithm:62:0,
from /home/ripley/R/Lib32/Rcpp/include/RcppCommon.h:63,
from /home/ripley/R/Lib32/RcppArmadillo/include/RcppArmadilloForward.h:26,
from /home/ripley/R/Lib32/RcppArmadillo/include/RcppArmadillo.h:31,
from ParallelFunctions.h:4,
from ParallelFunctions.cpp:1:
/opt/csw/include/c++/5.2.0/bits/stl_algo.h:4201:5: note: candidate: template<class _IIter1, class _IIter2, class _OIter, class _BinaryOperation> _OIter std::transform(_IIter1, _IIter1, _IIter2, _OIter, _BinaryOperation)
transform(_InputIterator1 __first1, _InputIterator1 __last1,
^
/opt/csw/include/c++/5.2.0/bits/stl_algo.h:4201:5: note: template argument deduction/substitution failed:
ParallelFunctions.cpp:134:27: note: candidate expects 5 arguments, 4 provided
::exp);
^
2.For the r-devel-linux-x86_64-fedora-clang:
hpaML.cpp:754:45: warning: explicitly assigning value of variable of type 'Rcpp::NumericVector' (aka 'Vector<14>') to itself [-Wself-assign-overloaded]
mean_ind, sd_ind = sd_ind,
~~~~~~ ^ ~~~~~~
ParallelFunctions.cpp:46:7: error: no matching function for call to 'transform'
std::transform(input.begin() + begin,
^~~~~~~~~~~~~~
/usr/local/bin/../include/c++/v1/algorithm:1955:1: note: candidate template ignored: couldn't infer template argument '_BinaryOperation'
transform(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2,
^
/usr/local/bin/../include/c++/v1/algorithm:1945:1: note: candidate function template not viable: requires 4 arguments, but 5 were provided
transform(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _UnaryOperation __op)
^
Here is the code for the function where std::tansform and std::exp functions have been called:
// Parallel exp of vectors
struct ParallelVectorExpStruct : public Worker
{
// source matrix
const RVector<double> input;
// destination matrix
RVector<double> output;
// initialize with source and destination
ParallelVectorExpStruct(const NumericVector input, NumericVector output)
: input(input), output(output) {}
// take the exponents of the range of elements requested
void operator()(std::size_t begin, std::size_t end) {
std::transform(input.begin() + begin,
input.begin() + end,
output.begin() + begin,
::exp);
}
};
// Parallel exponent of vector elements
NumericVector ParallelVectorExp(NumericVector x)
{
// allocate the output matrix
NumericVector output(x.size());
// ParallelVectorPowStruct functor
ParallelVectorExpStruct parallelVectorExpStruct(x, output);
// call parallelFor to do the work
parallelFor(0, x.length(), parallelVectorExpStruct);
// return the output matrix
return (output);
}
My descriptions file includes SystemRequirements: GNU make
My makevars file has the following flags
CXX_STD = CXX11
PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS)
PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
PKG_LIBS += $(shell ${R_HOME}/bin/Rscript -e "RcppParallel::RcppParallelLibs()")
Please help me to figure out how to resolve the error. Will be very great full for help!
I have found a strange solution. The idea is to make the following wrapper function:
double exp_parallel(double x)
{
return std::exp(x);
}
Then I substitute exp with exp_parallel yielding:
// Parallel exp of vectors
struct ParallelVectorExpStruct : public Worker
{
// source matrix
const RVector<double> input;
// destination matrix
RVector<double> output;
// initialize with source and destination
ParallelVectorExpStruct(const NumericVector input, NumericVector output)
: input(input), output(output) {}
// take the exponents of the range of elements requested
void operator()(std::size_t begin, std::size_t end) {
std::transform(input.begin() + begin,
input.begin() + end,
output.begin() + begin,
::exp_parallel);
}
};
Maybe the reason is that some systems can't distinguish between std::exp and Rcpp::exp functions.

Own vector assign implementation

I'm implementing stl like vector with writing all default functions. And there is a problem that I don't understand why It calls ragne version of assign for simple types and doesn't default.
Here is the implementation code:
Vector.h
void assign(size_t count, const T& value){ // Default version
void assign(size_t count, const T& value){
if(this->_size < count){
this->allocator.deallocate(this->arr, this->_capacity);
this->arr = this->allocator.allocate(count);
this->_capacity = count;
}
for(size_t i = 0; i < count; ++i)
this->arr[i] = value;
this->_size = count;
}
template<class InputIt>
void assign(InputIt first, InputIt last){ // Range version
size_t count = std::distance(first,last);
if(this->_size < count){
this->allocator.deallocate(this->arr, this->_capacity);
this->arr = this->allocator.allocate(count);
this->_capacity = count;
}
for(size_t i = 0; first != last; i++)
this->arr[i] = *first++;
this->_size = count;
}
Main code:
Vector<int> vec;
vec.assign(5,10);
Output:
/MyVector/MyVector.h: In instantiation of ‘void Vector<T, Allocator>::assign(InputIt, InputIt) [with InputIt = int; T = int; Allocator = std::allocator]’:
../MyVector/main.cpp:52:24: required from here
../MyVector/MyVector.h:99:45: error: no matching function for call to ‘distance(int&, int&)’
size_t count = std::distance(first,last);
~~~~~~~~~~~~~^~~~~~~~~~~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:66:0,
from /usr/include/c++/7/bits/char_traits.h:39,
from /usr/include/c++/7/ios:40,
from /usr/include/c++/7/ostream:38,
from /usr/include/c++/7/iostream:39,
from ../MyVector/main.cpp:1:
/usr/include/c++/7/bits/stl_iterator_base_funcs.h:138:5: note: candidate: template<class _InputIterator> constexpr typename std::iterator_traits<_Iterator>::difference_type std::distance(_InputIterator, _InputIterator)
distance(_InputIterator __first, _InputIterator __last)
^~~~~~~~
/usr/include/c++/7/bits/stl_iterator_base_funcs.h:138:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/bits/stl_iterator_base_funcs.h: In substitution of ‘template<class _InputIterator> constexpr typename std::iterator_traits<_Iterator>::difference_type std::distance(_InputIterator, _InputIterator) [with _InputIterator = int]’:
../MyVector/MyVector.h:99:45: required from ‘void Vector<T, Allocator>::assign(InputIt, InputIt) [with InputIt = int; T = int; Allocator = std::allocator]’
../MyVector/main.cpp:52:24: required from here
/usr/include/c++/7/bits/stl_iterator_base_funcs.h:138:5: error: no type named ‘difference_type’ in ‘struct std::iterator_traits<int>’
In file included from ../MyVector/main.cpp:2:0:
../MyVector/MyVector.h: In instantiation of ‘void Vector<T, Allocator>::assign(InputIt, InputIt) [with InputIt = int; T = int; Allocator = std::allocator]’:
../MyVector/main.cpp:52:24: required from here
../MyVector/MyVector.h:107:36: error: invalid type argument of unary ‘*’ (have ‘int’)
this->arr[i] = *first++;
^~~~~~~~
Makefile:725: recipe for target 'main.o' failed
make: *** [main.o] Error 1
I'm using C++17
The range version is a better match for vec.assign(5, 10); with InputIt = int. You should somehow disable that overload for a template parameter that doesn't represent an input iterator.
Let's take a look at stdlibc++ implementation:
template<typename InputIt, typename = std::RequireInputIter<InputIt>>
void assign(InputIt first, InputIt last) {
M_assign_dispatch(first, last);
}
where RequireInputIter is
template<typename InputIt>
using RequireInputIter = typename enable_if<is_convertible<typename
iterator_traits<InputIt>::iterator_category, input_iterator_tag>::value>::type;
In other words, for a deduced type InputIt, iterator_traits<InputIt>::iterator_category type should be convertible into input_iterator_tag. Otherwise, that assign overload is silently excluded from the overload resolution set thanks to SFINAE.
In C++17, RequireInputIter can be simplified with _t and _v helpers:
template<typename InputIt>
using RequireInputIter = enable_if_t<is_convertible_v<typename
iterator_traits<InputIt>::iterator_category, input_iterator_tag>>;
Also note that input iterators can be used to traverse a range only once. After you call std::distance(first, last), all subsequent attempts to traverse the range are undefined behaviour unless InputIt is at least a forward iterator. For input iterators you can't determine how much space to preallocate.
That's why assign uses tag dispatch technique internally. With some simplifications it looks like this:
template<typename InputIt, typename = std::RequireInputIter<InputIt>>
void assign(InputIt first, InputIt last) {
M_assign_aux(first, last,
typename iterator_traits<InputIt>::iterator_category{});
}
There are two M_assign_aux overloads
template<typename InputIt>
void M_assign_aux(InputIt first, InputIt last, std::input_iterator_tag);
template<typename ForwardIt>
void M_assign_aux(ForwardIt first, ForwardIt last, std::forward_iterator_tag);
to do the assignment. The first one will be used for input iterators only, and the second one - for forward iterators and those derived from it, i.e. bidirectional and random access ones.
You can call a specific function using cast. Like:
assign( (size_t) 5, (const int&) 10);

A functor(inherrited) is forbidden when using std::sort?

#include <string.h>
#include <vector>
#include <algorithm>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/regex.hpp>
struct FileSorter{
virtual ~FileSorter(){}
virtual bool operator()(const boost::filesystem::path& p1, const boost::filesystem::path& p2) const =0;
};
struct SortByName : public FileSorter{
SortByName(bool ascending=true):ascending_order(ascending)
{
}
virtual bool operator()(const boost::filesystem::path& p1, const boost::filesystem::path& p2) const {
if(ascending_order)
return p1.stem().string() < p2.stem().string();
else
return p1.stem().string() > p2.stem().string();
}
protected:
bool ascending_order;
};
class FilesList : public std::vector<boost::filesystem::path> {
public:
FilesList(const std::string& dir, const std::string& f_regex, const FileSorter& fileSorter=SortByName()) {
boost::regex e(f_regex, boost::regex::perl);
boost::filesystem::path path(dir);
if(!boost::filesystem::is_directory(path)) {
throw std::runtime_error(path.string()+std::string(" is not a directory\n"));
}
for(boost::filesystem::directory_iterator file(path), f_end; file!= f_end; ++file){
if(boost::regex_match(file->path().filename().string(), e))
this->push_back(file->path());
}
std::sort(this->begin(), this->end(), fileSorter);
}
};
I defined a class FileList which do perform create a list of files which meet the regular expression(f_regex argument).
To sort the list, an instance of SortBy*** struct(inherited from FileSorter) can be passed.
The problem is std::sort function cannot be compiled with the code above showing the following error message.
/usr/include/c++/4.8/bits/stl_algo.h:5483:5: error: cannot allocate an object of abstract type ‘FileSorter’
I don't understand this behavior. In my narrow knowledge, struct equipped with operator () is called functor and it is a good way to deal with a function as an object.
And as all we know, instance of child class can be referred by a reference of parent class.
But the above example is saying differently.
What should I change to make the code work?
If I have wrong concepts about c++, please don't hesitate to scold me.
Full compile error messages are here.
$ make
Scanning dependencies of target cpp_factory
[ 11%] Building CXX object CMakeFiles/cpp_factory.dir/libraries/src/FileLister.cpp.o
In file included from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:0:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h: In constructor ‘FilesList::FilesList(const string&, const string&, const FileSorter&)’:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:109:57: error: no matching function for call to ‘sort(std::vector<boost::filesystem::path>::iterator, std::vector<boost::filesystem::path>::iterator, const FileSorter&)’
std::sort(this->begin(), this->end(), fileSorter);
^
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:109:57: note: candidates are:
In file included from /usr/include/c++/4.8/algorithm:62:0,
from /home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:11,
from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:
/usr/include/c++/4.8/bits/stl_algo.h:5447:5: note: template<class _RAIter> void std::sort(_RAIter, _RAIter)
sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
^
/usr/include/c++/4.8/bits/stl_algo.h:5447:5: note: template argument deduction/substitution failed:
In file included from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:0:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:109:57: note: candidate expects 2 arguments, 3 provided
std::sort(this->begin(), this->end(), fileSorter);
^
In file included from /usr/include/c++/4.8/algorithm:62:0,
from /home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:11,
from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:
/usr/include/c++/4.8/bits/stl_algo.h:5483:5: note: template<class _RAIter, class _Compare> void std::sort(_RAIter, _RAIter, _Compare)
sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
^
/usr/include/c++/4.8/bits/stl_algo.h:5483:5: note: template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/stl_algo.h: In substitution of ‘template<class _RAIter, class _Compare> void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<boost::filesystem::path*, std::vector<boost::filesystem::path> >; _Compare = FileSorter]’:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:109:57: required from here
/usr/include/c++/4.8/bits/stl_algo.h:5483:5: error: cannot allocate an object of abstract type ‘FileSorter’
In file included from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:0:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:49:8: note: because the following virtual functions are pure within ‘FileSorter’:
struct FileSorter{
^
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:51:18: note: virtual bool FileSorter::operator()(const boost::filesystem::path&, const boost::filesystem::path&) const
virtual bool operator()(const boost::filesystem::path& p1, const boost::filesystem::path& p2) const =0;
^
make[2]: *** [CMakeFiles/cpp_factory.dir/libraries/src/FileLister.cpp.o] Error 1
make[1]: *** [CMakeFiles/cpp_factory.dir/all] Error 2
make: *** [all] Error 2
If you look at the signature, std::sort takes its comparison object by value:
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
So when you write:
std::sort(this->begin(), this->end(), fileSorter);
your object gets sliced, and you end up trying to instantiate a function which takes an abstract class by value, hence all the errors you end up with.
What you need to do is ensure that even though sort takes its comparison by value, you pass yours in by reference. Thankfully, there's an app for that! Just use std::ref:
std::sort(this->begin(), this->end(), std::ref(fileSorter));
That said, do you really need a polymorphic comparator? If you're just passing in different comparison function objects into the FilesList constructor, you should prefer to just make it a function template:
template <class Sorter>
FilesList(const std::string& dir, const std::string& f_regex, Sorter fileSorter) {
// ...
std::sort(begin(), end(), fileSorter); // now copying is fine
}
That way, you can just directly forward in what the user passes and avoid virtual dispatch.
Your FileSorter argument is defaulted to a SortByExtension object rather than a SortByName object. As you haven't included the source of SortByExtension, I would start by checking that function signature of SortByExtension's function call operator is
bool SortByExtension::operator()(const path&, const path&) const
If there are any differences between the base class and derived class function signatures, the derived class function won't override the base class one, and the derived class will be treated as an abstract class.

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.