#include <vector>
struct A {int a;};
struct B : public A {char b;};
int main()
{
B b;
typedef std::pair<A*, A*> MyPair;
std::vector<MyPair> v;
v.push_back(std::make_pair(&b, &b)); //compiler error should be here(pair<B*,B*>)
return 0;
}
I don't understand why this compiles (maybe somebody can kindly provide detailed explanation? Is it something related to name look-up?
Btw, on Solaris, SunStudio12 it doesn't compile: error : formal argument x of type const std::pair<A*, A*> & in call to std::vector<std::pair<A*,A*> >::push_back(const std::pair<A*, A*> & ) is being passed std::pair<B*, B*>
std::pair has a constructor template:
template<class U, class V> pair(const pair<U, V> &p);
"Effects: Initializes members from the corresponding members of the argument, performing implicit conversions as needed." (C++03, 20.2.2/4)
Conversion from a derived class pointer to a base class pointer is implicit.
Because B is derived from A, the vector v will contain pointers to base class structures of the object b. therefore, you could access the members of A, i.e.
std::cout << v[0].first->a;
EDIT:
My mistake, as pointed out below, you can still cast to pointers of type B since the vector is of pointers, not objects, so no object slicing has occurred.
A call such as
std::cout << v[0].first->b;
will not compile since the elements in the vector are base class pointers and cannot point to derived class members without a cast, i.e.
std::cout << static_cast<B*>(v[0].first)->b;
Also note that a dynamic cast, as in
std::cout << dynamic_cast<B*>(v[0].first)->b;
will not compile with the following error in gcc:
cast.cpp:14: error: cannot dynamic_cast ‘v.std::vector<_Tp, _Alloc>::operator[] [with _Tp = std::pair<A*, A*>, _Alloc = std::allocator<std::pair<A*, A*> >](0u)->std::pair<A*, A*>::first’ (of type struct A*’) to type struct B*’ (source type is not polymorphic)
Related
As stated in this answer a std::vector<T> cannot contain const T, or classes with const-members. However, this is not the case when T = std::pair<const int, int>, as shown below. Why is this the case? How is std::pair special?
#include <utility>
#include <vector>
struct foo
{
const int first;
int second;
};
int main() {
std::vector<std::pair<const int, int>> V1;
V1.resize(3); // This compiles
std::vector<foo> V2;
V2.resize(3); // This gives the error listed below
}
error: use of deleted function 'foo::foo()'
note: 'foo::foo()' is implicitly deleted because the default definition would be ill-formed:
You are mixing two things here. The error that you get is due to the implicitly deleted foo() default constructor that std::vector::resize(size_type count) invokes:
If the current size is less than count,
1) additional default-inserted elements are appended
The std::pair template has a default constructor, this is why the call to V1.resize succeeds. If you provide one for foo as well, or allow its implicit generation by in class initialization, e.g.
struct foo
{
const int first = 42;
int second = 43;
};
then
std::vector<foo> V2;
V2.resize(3);
will happily compile. The operation that won't work out for both std::pair<const int, int> and foo is assignment. This won't compile:
V1[0] = std::pair<const int, int>(42, 43); // No way
V2[0] = { 42, 43 }; // Also not ok, can't assign to const data member
which doesn't have anything to do with std::vector, but with the const-qualified data members in both cases.
I'm trying to implement unordered_map with pointer to custom class as key and integer as value.
I thought pointer is just an address, so I wouldn't have to create comparison template for unordered_map, since map would compare between addresses. But I get compile error.
My code is as follow for simple testing. Can anyone help me to fix what have I done wrong?
#include <cstdlib>
#include <unordered_map>
#include <iostream>
using namespace std;
class MyClass{
public:
MyClass(int id){m_id = id;};
void PrintThis(){cout << " This is test " << endl;};
int m_id;
};
class Test{
public:
unordered_map<MyClass* mc, int test> mapTest;
};
int main(){
MyClass* mc1 = new MyClass(1);
MyClass* mc2 = new MyClass(2);
Test* tt1 = new Test();
tt1->mapTest.insert(make_pair<MyClass*, int>(mc1, 10));
tt1->mapTest.insert(make_pair<MyClass*, int>(mc2, 20));
auto search = tt1->find(mc1);
if(search != tt1->end()) {
search->first->PrintThis();
}else{
cout << "not Found " << endl;
}
}
Error message is as follow
./main.cpp:17:44: error: wrong number of template arguments (1, should be 5)
unordered_map<MyClass* mc, int test> mapTest;
^
In file included from /usr/include/c++/4.8/unordered_map:48:0,
from ./main.cpp:2:
/usr/include/c++/4.8/bits/unordered_map.h:97:11: error: provided for 'template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> class std::unordered_map'
class unordered_map : __check_copy_constructible<_Alloc>
^
./main.cpp: In function 'int main()':
./main.cpp:26:18: error: request for member 'insert' in 'tt1->Test::mapTest', which is of non-class type 'int'
tt1->mapTest.insert(make_pair<MyClass*, int>(mc1, 10));
I think I can manage line 26 error, if line 17 gets fixed...
Thanks in advance!
I tried your code and found 3 problems:
Declaration of map: it should read std::unordered_map<MyClass*, int>
call of undefined functions (tt1->find/tt1->end, should read tt1->testMap.XXX)
Call of make_pair doesn't require template arguments. The compiler will infer them. This actually causes a problem, as the compiler tries to call make_pair(MyClass *&&, int &&). If I omit the template arguments, it works (make_pair(mc1, 10))
As for point 3:
make_pair is declared as follows in C++11 (C++14 just adds constexpr) (cppreference):
template< class T1, class T2 >
std::pair<V1,V2> make_pair( T1&& t, T2&& u );
For template argument deduction, the follwing rule applies (cf. cppreference)
4) If P is an rvalue reference to a cv-unqualified template parameter (so-called "forwarding reference"), and the corresponding function call argument is an lvalue, the type lvalue reference to A is used in place of A for deduction (Note: this is the basis for the action of std::forward)
(emphasis mine)
So the compiler will infer:
std::make_pair<MyClass *&, int>(MyClass *&, int &&);
where MyClass *& can bind to your actual argument.
If you directly specify the template types, the compiler will stick to
std::make_pair<MyClass *, int>(MyClass *&&, int &&).
As your argument is a lvalue, it cannot be converted to a rvalue-reference, and compilation fails
Your declaration of unordered_map<MyClass* mc, int test> mapTest; is invalid syntax. It should be unordered_map<MyClass*, int> mapTest.
Also remove the template parameters from your make_pair calls and change tt1->find to ttl->mapTest.find() and ttl->end() to ttl->mapTest.end().
all. I am trying to learn something about template inherit. I want to cast a temp derived object to its base reference. But I come across this problem:
typedef long size64_t;
//////Base class
template <typename _Scalar>
class MatrixBase{
public:
virtual _Scalar operator()(size64_t rowid, size64_t colid) = 0;
};
//////Derived class 1
template <typename _Scalar>
class MatrixHolder : public MatrixBase<_Scalar>{
public:
MatrixHolder(){};
inline _Scalar operator()(size64_t rowid, size64_t colid){return 0;}
};
//////Derived class 2
template <typename _Scalar>
class Matrix : public MatrixBase<_Scalar>{
public:
Matrix(){};
inline _Scalar operator()(size64_t rowid, size64_t colid){return 0;}
};
//////The function with parameters as Base class reference, wanting to get derived object as input.
template <typename _Scalar>
MatrixHolder<_Scalar> apply(MatrixBase<_Scalar>& lhs, MatrixBase<_Scalar>& rhs){
MatrixHolder<_Scalar> result;
return result;
}
and in main, we have:
void main(){
Matrix<double> m1;
Matrix<double> m2;
apply(m1, m2);//Sucess
apply(m1, apply(m1, m2));//Fail
}
the compiler said:
note: candidate function [with _Scalar = double] not viable: no known conversion from
'MatrixHolder<double>' to 'MatrixBase<double> &' for 2nd argument
MatrixHolder<_Scalar> apply(MatrixBase<_Scalar>& lhs, MatrixBase<_Scalar>& rhs){
^
1 error generated.
apply(m1, apply(m1, m2));//Fail
The problem here is that the inner apply returns a temporary, which cannot bind to the non-const reference parameter of the outer apply.
If you can make the parameters MatrixBase<_Scalar> const& it would be a possible match.
I'm trying to use boost::mpl::inherit_linearly to compose a container class using types provided by the user:
#include <typeinfo>
#include <iostream>
#include <vector>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/vector.hpp>
namespace mpl = ::boost::mpl;
//////////////////////////////////////////////
// Create the container by chaining vectors
//////////////////////////////////////////////
struct Base {};
// Types provided by the user
typedef mpl::vector<int, char, double>::type myTypes;
typedef mpl::inherit_linearly<
myTypes,
mpl::inherit<mpl::_1, std::vector<mpl::_2> >,
Base
>::type InheritedContainer;
// Function for accessing containers
template <typename T>
inline std::vector<T>& get_container(Base& c) {
return static_cast<std::vector<T>& >(c);
}
// Some functions that manipulate the containers
// NB: These functions only know about the Base and the types
// they want to access
void my_int_func(Base& b) {
get_container<int>(b).push_back(42);
}
void my_char_func(Base& b) {
get_container<char>(b).push_back('c');
}
int main() {
InheritedContainer container;
Base& bref = container;
my_int_func(bref);
std::cout << "Int: " << get_container<int>(bref).back() << std::endl;
my_char_func(bref);
std::cout << "Char: " << get_container<char>(bref).back() << std::endl;
return 0;
}
The compile error I get is:
question.cpp: In function ‘std::vector<T, std::allocator<_CharT> >& get_container(Base&) [with T = int]’:
question.cpp:40: instantiated from here
question.cpp:31: error: invalid static_cast from type ‘Base’ to type ‘std::vector<int, std::allocator<int> >&’
question.cpp: In function ‘std::vector<T, std::allocator<_CharT> >& get_container(Base&) [with T = char]’:
question.cpp:44: instantiated from here
question.cpp:31: error: invalid static_cast from type ‘Base’ to type ‘std::vector<char, std::allocator<char> >&’
Shouldn't Base be a base of whatever type is produced by inherit_linearly? And if so, shouldn't a vector<int> and the other vectors show up in the type hierarchy for static_cast to pull out?
Is there any other way to get this functionality?
I think Base is a base class of InheritedContainer, but not of
std::vector<int>.
As we know, std::vector isn't defined as the following:
class vector : Base {...
You may expect the following inheritance:
class InheritedContainer : Base, std::vector<int>, ... {...
However, in this case, the cast from Base to vector<int> is a cross-cast,
so this cannot be done with static_cast.
As you may know, the following is allowed:
InheritedContainer container;
Base& bref = container;
InheritedContainer& iref = static_cast<InheritedContainer&>(bref);
std::vector<int>& vi = iref;
std::vector<char>& vc = iref;
If you can prepare get_container, my_int_func and my_char_func, probably the types
to which the std::vector will be specialized are known beforehand.
If so, I suppose it is pertinent to hold InheritedContainer& instead of Base&
all along.
If you have to cast Base to vector<T>, probably
RTTI(for example adding virtual function to Base) and dynamic_cast will enable
the cast.
The offending code:
template<typename T>
class SharedObject {
public:
typedef boost::intrusive_ptr<T> Pointer;
typedef boost::intrusive_ptr<T const> ConstPointer;
inline Pointer GetPointer() {
return Pointer(this); //Ambiguous call here
}
inline ConstPointer GetPointer() const {
return ConstPointer(this);
}
...
and used like this:
template <typename T>
class SomeClass: public SharedObject<SomeClass<T> > {
public:
static inline boost::intrusive_ptr<SomeClass<T> > Create() {
return (new SomeClass)->GetPointer();
}
};
int main()
{
auto v = SomeClass<int>::Create();
}
GCC (4.4.1) with boost 1.41 gives this error upon instatiating the first (non-const) version of GetPointer():
error: call of overloaded ‘intrusive_ptr SharedObject<SomeClass<int> >* const)’ is ambiguous
boost/smart_ptr/intrusive_ptr.hpp:118: note: candidates are: boost::intrusive_ptr<T>::intrusive_ptr(boost::intrusive_ptr<T>&&) [with T = SomeClass<int>] <near match>
boost/smart_ptr/intrusive_ptr.hpp:94: note: boost::intrusive_ptr<T>::intrusive_ptr(const boost::intrusive_ptr<T>&) [with T = SomeClass<int>] <near match>
boost/smart_ptr/intrusive_ptr.hpp:70: note: boost::intrusive_ptr<T>::intrusive_ptr(T*, bool) [with T = SomeClass<int>] <near match>
To my less than arcane skills in C++, I can't see why there is any ambiguity at all. The two canditates at lines 188 and 94 takes an existing intrusive_ptr rvalue reference, which SharedObject::this certainly is not. The final candidate however is a perfect match (the bool argument is optional).
Anyone care to enlighten me as to what the problem is?
EDIT+answer: I finally realized that in
inline Pointer GetPointer() {
return Pointer(this); //Ambiguous call here
}
this refers to SharedObject while the Pointer typedef is SomeClass. (Which is pretty much what Butterworth pointed out right away).
inline Pointer GetPointer() {
return Pointer(static_cast<C*>(this));
}
Since I know this to really be SomeClass, inheriting from SharedObject, a static_cast makes the template class go 'round.
When you say:
typedef boost::intrusive_ptr<T> Pointer;
you are declaring a type which is an intrusive pointer to an int (because T is an int at that point), when the template is instantiated in your code. Your SharedObject class is not an int, so you can't instantiate such an intrusive pointer using this.
Edit: OK, I misunderstood your code, I'll try again. At:
return Pointer(this); //Ambiguous call here
this is a SharedObject , as per the error messages, however the pointer is typedefed to a SomeClass I think.
Your code is incredibly hard to understand - whatever it is you are trying to do, there must be a simpler way. And you seem to be missing a virtual destructor (and maybe a virtual function) in the base class.