I'm learning boost and smart pointers. During compilation I got an error, and I can't figure out what is it about. I don't understand what I am doing wrong. The problem is in constructor:
DefaultCreature(const Creature& def) : def_(def) {}
Here is my code:
#include <iostream>
#include <boost/smart_ptr.hpp>
using namespace std;
using namespace boost;
class Creature;
typedef shared_ptr<Creature> PCreature;
class Creature {
public:
Creature(const string& name) : name_(name) {}
const string& getName() const { return name_; }
private:
string name_;
};
class DefaultCreature {
public:
DefaultCreature(const Creature& def) : def_(def) {}
private:
PCreature def_;
};
int main() {
DefaultCreature factory(Creature("lion"));
return 0;
}
And an error:
exercise1.cpp: In constructor ‘DefaultCreature::DefaultCreature(const Creature&)’:
exercise1.cpp:20:52: error: no matching function for call to ‘boost::shared_ptr<Creature>::shared_ptr(const Creature&)’
exercise1.cpp:20:52: note: candidates are:
In file included from /usr/local/include/boost/shared_ptr.hpp:17:0,
from /usr/local/include/boost/smart_ptr.hpp:21,
from exercise1.cpp:2:
/usr/local/include/boost/smart_ptr/shared_ptr.hpp:472:14: note: template<class Ap> boost::shared_ptr::shared_ptr(Ap, typename boost::detail::sp_enable_if_auto_ptr<Ap, int>::type)
/usr/local/include/boost/smart_ptr/shared_ptr.hpp:472:14: note: template argument deduction/substitution failed:
/usr/local/include/boost/smart_ptr/shared_ptr.hpp: In substitution of ‘template<class Ap> boost::shared_ptr::shared_ptr(Ap, typename boost::detail::sp_enable_if_auto_ptr<Ap, int>::type) [with Ap = Creature]’:
exercise1.cpp:20:52: required from here
/usr/local/include/boost/smart_ptr/shared_ptr.hpp:472:14: error: no type named ‘type’ in ‘struct boost::detail::sp_enable_if_auto_ptr<Creature, int>’
/usr/local/include/boost/smart_ptr/shared_ptr.hpp:446:14: note: template<class Y> boost::shared_ptr::shared_ptr(std::auto_ptr<_Tp1>&)
/usr/local/include/boost/smart_ptr/shared_ptr.hpp:446:14: note: template argument deduction/substitution failed:
exercise1.cpp:20:52: note: types ‘std::auto_ptr<T>’ and ‘const Creature’ have incompatible cv-qualifiers
(...)
/usr/local/include/boost/smart_ptr/shared_ptr.hpp:339:5: note: boost::shared_ptr<T>::shared_ptr() [with T = Creature]
/usr/local/include/boost/smart_ptr/shared_ptr.hpp:339:5: note: candidate expects 0 arguments, 1 provided
/usr/local/include/boost/smart_ptr/shared_ptr.hpp:328:25: note: boost::shared_ptr<Creature>::shared_ptr(const boost::shared_ptr<Creature>&)
/usr/local/include/boost/smart_ptr/shared_ptr.hpp:328:25: note: no known conversion for argument 1 from ‘const Creature’ to ‘const boost::shared_ptr<Creature>&’
The argument to shared_ptr must be the address of a dynamically allocated object but the code is passing in a reference. Change to, for example:
class DefaultCreature {
public:
DefaultCreature(const Creature& def) : def_(new Creature(def)) {}
private:
PCreature def_;
};
or using boost::make_shared:
class DefaultCreature {
public:
DefaultCreature(const Creature& def) :
def_(boost::make_shared<Creature>(def)) {}
private:
PCreature def_;
};
If the instance of DefaultCreature is the only object that has access to the object being pointed to by def_ then there is no reason for it to be a boost::shared_ptr: use boost::scoped_ptr instead. See What C++ Smart Pointer Implementations are available? for a very useful overview of smart pointers.
However, from the posted code there appears to be no reason to be using pointers of any nature. Just store a Creature instance in DefaultCreature (Creature is copyable and there is no polymorphic requirement, based on the posted code).
Related
I would like to inherit from STL priority queue to have some additional functionality such as:
allowing removal. But I am struggling to make this work when I use custom comparators. MWE:
#include <queue>
template<typename T, class Container=std::vector<T>, class Compare=std::less<typename Container::value_type>>
class custom_priority_queue : public std::priority_queue<T, Container, Compare>
{
public:
// My additional functions here.
};
int main()
{
auto pq_comp = [](const int& a, const int& b) { return a <= b; };
std::priority_queue<int, std::vector<int>, decltype(pq_comp)> pq(pq_comp); // works
custom_priority_queue<int> pq_custom; // works
custom_priority_queue<int, std::vector<int>, decltype(pq_comp)> pq_custom2(pq_comp); // Error
return 0;
}
The error is:
main.cpp: In function ‘int main()’:
main.cpp:15:87: error: no matching function for call to ‘custom_priority_queue, main():: >::custom_priority_queue(main()::&)’
15 | custom_priority_queue<int, std::vector<int>, decltype(pq_comp)> pq_custom2(pq_comp); // Error
| ^
main.cpp:4:7: note: candidate: ‘custom_priority_queue, main():: >::custom_priority_queue(const custom_priority_queue, main():: >&)’
4 | class custom_priority_queue : public std::priority_queue<T, Container, Compare>
| ^~~~~~~~~~~~~~~~~~~~~
main.cpp:4:7: note: no known conversion for argument 1 from ‘main()::’ to ‘const custom_priority_queue, main():: >&’
main.cpp:4:7: note: candidate: ‘custom_priority_queue, main():: >::custom_priority_queue(custom_priority_queue, main():: >&&)’
main.cpp:4:7: note: no known conversion for argument 1 from ‘main()::’ to ‘custom_priority_queue, main():: >&&’
Constructors are not automatically inherited, so your class probably lacks any constructor, except the implicitly-declared ones.
You can explicitly inherit all constructors of the base class:
template<typename T, class Container=std::vector<T>, class Compare=std::less<typename Container::value_type>>
class custom_priority_queue : public std::priority_queue<T, Container, Compare>
{
// inherit constructors
using priority_queue::priority_queue;
public:
// My additional functions here.
};
I can't understand how i can create expr object from double in expr.cpp file.
expr_base:
The base class of all expressions. Note that all expression classes
(including this base) are private to the implementation and should not
be exposed to other code. The rest of the program should use
expressions only via expr.
This subclasses std::enable_shared_from_this to enable getting
shared_ptr to this from a method.
expr:
Wrapper around dynamically allocated instances of expr_base. This type
has value semantics and since all subclasses of expr_base are
immutable, shallow copies are made.
This type has overloaded functions and operators, so that expression
construction is easy and readable.
error:
error: no viable conversion from returned value of type 'typename enable_if<!is_array<number>::value,
shared_ptr<number> >::type' (aka 'std::__1::shared_ptr<exprs::number>') to function return type 'expr'
return std::make_shared<exprs::number>(n);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/..../expr.hpp(...): note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'typename enable_if<!is_array<number>::value, shared_ptr<number> >::type' (aka 'std::__1::shared_ptr<exprs::number>') to 'const expr &' for 1st argument
class expr final {
^
/.../expr.hpp:(...): note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'typename enable_if<!is_array<number>::value, shared_ptr<number> >::type' (aka 'std::__1::shared_ptr<exprs::number>') to 'expr &&' for 1st argument
/.../expr.hpp:(...): note: candidate template ignored: requirement 'std::is_convertible<exprs::number *, const expr_base*>::value' was not satisfied [with T = exprs::number]
expr(std::shared_ptr<T> e): ptr(std::static_pointer_cast<const expr_base>(std::move(e))) {}
expr.hpp
...
class expr;
class expr_base: public std::enable_shared_from_this<expr_base>
{
friend class expr;
protected:
expr_base() = default;
public:
using variable_map_t = std::map<std::string, double>;
virtual ~expr_base() = default;
};
class expr final {
private:
using const_pointer = std::shared_ptr<const expr_base>;
public:
using variable_map_t = expr_base::variable_map_t;
template <typename T, typename = std::enable_if_t<std::is_convertible<T*, const expr_base*>::value>>
expr(std::shared_ptr<T> e): ptr(std::static_pointer_cast<const expr_base>(std::move(e))) {}
expr() = default;
static expr number(double n);
operator const_pointer const &() const {return ptr;}
const expr_base* operator->() const {assert(ptr.get() != nullptr); return ptr.get();}
private:
const_pointer ptr;
};
expr.cpp
...
#include "expr.hpp"
#include "expr_impl.hpp"
expr expr::number(double n) {
return std::make_shared<exprs::number>(n); // It doesn't work
}
expr_impl.hpp
...
#include "expr.hpp"
namespace exprs {
class number:expr_base {
private:
double num_;
public:
number(double num): num_(num) {};
};
}
#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.
I have the following code:
#include <memory>
int main()
{
int* a = new int(2);
std::unique_ptr<decltype(*a)> p(a);
}
which leads to these error message:
In file included from a.cpp:1:
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/memory:81:
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/unique_ptr.h:138:14: error: '__test' declared as a pointer to a reference of type 'int &'
static _Tp* __test(...);
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/unique_ptr.h:146:35: note: in instantiation of member class 'std::unique_ptr<int &,
std::default_delete<int &> >::_Pointer' requested here
typedef std::tuple<typename _Pointer::type, _Dp> __tuple_type;
^
a.cpp:7:35: note: in instantiation of template class 'std::unique_ptr<int &, std::default_delete<int &> >' requested here
std::unique_ptr<decltype(*a)> p(a);
^
In file included from a.cpp:1:
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/memory:81:
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/unique_ptr.h:227:33: error: 'type name' declared as a pointer to a reference of type 'int &'
is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>>
^
a.cpp:7:35: note: in instantiation of template class 'std::unique_ptr<int &, std::default_delete<int &> >' requested here
std::unique_ptr<decltype(*a)> p(a);
^
2 errors generated.
I understand the reason is that the unique_ptr template expects type int, but decltype(*a) gives int&. In the case that int is a very long and complicated type, how can I make this code work with decltype?
Use std::decay_t. This is the conversion that is applied when you pass an argument to a function by value.
You can use a typedef inside a templated class and then use template specialisation, like this
template<typename T> struct unref {
typedef T raw;
};
template<typename T> struct unref<T&> {
typedef T raw;
};
int main() {
int* a = new int(2);
std::unique_ptr<unref<decltype(*a)>::raw> p(a);
}
i tried to use the old bind2nd function in this way:
template<typename T>
class printer
{
public:
void operator()(T a, string& kd)
{
cout<<a<<endl;
}
};
int main(int argc, char *argv[])
{
string nme = "J-dar";
auto f1 = bind2nd(printer<int>(),nme);
//f1(5);
return 0;
}
but i get a lot of errors:
required from here
error: no type named 'first_argument_type' in 'class printer<int>' class binder2nd ^
error: no type named 'second_argument_type' in 'class printer<int>' typename _Operation::second_argument_type value; ^
error: no type named 'second_argument_type' in 'class printer<int>' binder2nd(const _Operation& __x, ^
error: no type named 'result_type' in 'class printer<int>' operator()(const typename _Operation::first_argument_type& __x) const ^
error: no type named 'result_type' in 'class printer<int>' operator()(typename _Operation::first_argument_type& __x) const ^
required from here
error: no type named 'second_argument_type' in 'class printer<int>' typedef typename _Operation::second_argument_type _Arg2_type;
from what i can see it's all correct so i don't really know what is going on. ^
First of all: I would recommend using abandoning bind1st() and bind2nd(), which are deprecated in C+11, and in general the obsolete support for functional programming of the C++03 Standard Library.
You should rather use C++11's std::bind(), since it seems you can afford that - judging from the fact that you are using the auto keyword:
#include <functional>
// ...
auto f1 = std::bind(printer<int>(), std::placeholders::_1, nme);
This said, just for the record, the deprecated std::bind2nd() function requires some metadata about the signature of your functor's call operator, and it expects these metadata to be provided as type aliases in your functor class. For instance:
template<typename T>
class printer
{
public:
// These metadata must be present in order for bind1st and bind2nd to work...
typedef void result_type;
typedef T first_argument_type;
typedef string const& second_argument_type;
void operator()(T a, string const& kd) const
// ^^^^^ // Bonus advice #1:
// // This could and should be
// // const-qualified
// ^^^^^
// Bonus advice #2: why not taking by
// reference to const here? ;)
{
cout<<a<<endl;
}
};
A simpler way of achieving the above is to use the (also deprecated) class template std::binary_function as a base class, and let that class template define the appropriate type aliases:
template<typename T>
class printer : public std::binary_function<T, string const&, void>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
public:
void operator()(T a, string const& kd) const
{
cout<<a<<endl;
}
};
But again, please consider putting std::bind1st(), std::bind2nd(), as well as std::unary_function and std::binary_function, back in the drawer. They are superseded by C++11's more powerful support for functional programming.