I have this snippet of C++ code that doesn't compile under g++-4.9.1 (I used the command "g++ -c --std=c++11 map.cc")
#include <map>
#include <cstdint>
class A {
std::map<uint8_t, uint8_t> b = std::map<uint8_t, uint8_t>();
};
I get the following error when compiling:
map.cc:5:52: error: expected ‘;’ at end of member declaration
std::map<uint8_t, uint8_t> b = std::map<uint8_t, uint8_t>();
^
map.cc:5:52: error: declaration of ‘std::map<unsigned char, unsigned char> A::uint8_t’ [-fpermissive]
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.9/include/stdint.h:9:0,
from /usr/include/c++/4.9/cstdint:41,
from /usr/include/c++/4.9/bits/char_traits.h:380,
from /usr/include/c++/4.9/string:40,
from /usr/include/c++/4.9/stdexcept:39,
from /usr/include/c++/4.9/array:38,
from /usr/include/c++/4.9/tuple:39,
from /usr/include/c++/4.9/bits/stl_map.h:63,
from /usr/include/c++/4.9/map:61,
from map.cc:1:
/usr/include/stdint.h:48:24: error: changes meaning of ‘uint8_t’ from ‘typedef unsigned char uint8_t’ [-fpermissive]
typedef unsigned char uint8_t;
^
map.cc:5:59: error: expected unqualified-id before ‘>’ token
std::map<uint8_t, uint8_t> b = std::map<uint8_t, uint8_t>();
^
map.cc:5:43: error: wrong number of template arguments (1, should be 4)
std::map<uint8_t, uint8_t> b = std::map<uint8_t, uint8_t>();
^
In file included from /usr/include/c++/4.9/map:61:0,
from map.cc:1:
/usr/include/c++/4.9/bits/stl_map.h:96:11: error: provided for ‘template<class _Key, class _Tp, class _Compare, class _Alloc> class std::map’
class map
^
However, if I replace uint8_t with int, it compiles fine.
The problem with g++ is much larger, whenever you use a template as a class member, you cannot use member initialization if any parameter (except the first one), is a typedef or in another namespace.
typedef int I;
template<typename T1, typename T2> struct A {};
struct B {
A<I,float> a1=A<I,float>(); // works!
A<float,I> a2=A<float,I>(); // does not compile!
// This is the same reason the map does not comile, as string is a typedef
};
FWIW, if you need a work around, the following works:
class A {
typedef std::map<uint8_t, uint8_t> B;
B b = B();
};
Related
When I try to emplace an object which has a unique_ptr and a destructor into a map, I get a compiler error, shown below. However, when the object has no destructor defined, emplacement works just fine. What is going on?
How can I emplace an object which has a unique_ptr and a destructor defined into a map?
#include <map>
#include <iostream>
#include <string>
struct A {
std::string name;
std::unique_ptr<int> p;
virtual ~A(){}; // comment out this line
A(std::string n) : name(n) { }
};
int main()
{
std::map<int, A> m;
m.emplace(1, A("Name"));
return 0;
}
I'm using Apple clang version 11.0.0 on OSX
Compiler Error
In file included from main.cpp:1:
In file included from /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/map:480:
In file included from /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__tree:16:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:1826:31: error: no matching constructor for initialization of 'std::__1::pair<const int, B>'
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:1718:18: note: in instantiation of function template specialization
'std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<int, B>, void *> >::construct<std::__1::pair<const int, B>, int, B>' requested here
{__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:1561:14: note: in instantiation of function template specialization
'std::__1::allocator_traits<std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<int, B>, void *> > >::__construct<std::__1::pair<const int, B>,
int, B>' requested here
{__construct(__has_construct<allocator_type, _Tp*, _Args...>(),
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__tree:2212:20: note: in instantiation of function template specialization
'std::__1::allocator_traits<std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<int, B>, void *> > >::construct<std::__1::pair<const int, B>,
int, B>' requested here
__node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_), _VSTD::forward<_Args>(__args)...);
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__tree:2157:29: note: in instantiation of function template specialization
'std::__1::__tree<std::__1::__value_type<int, B>, std::__1::__map_value_compare<int, std::__1::__value_type<int, B>, std::__1::less<int>, true>,
std::__1::allocator<std::__1::__value_type<int, B> > >::__construct_node<int, B>' requested here
__node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
^
... [similar error messages come here]
main.cpp:19:11: note: in instantiation of function template specialization 'std::__1::map<int, B, std::__1::less<int>, std::__1::allocator<std::__1::pair<const
int, B> > >::emplace<int, B>' requested here
m.emplace(1, B("Name"));
^
std::map::emplace allows to create object in place by passing constructor's arguments and you don't need copy/move.
As mentions in one of comment that because of user provided distructor, compiler does not generate move constructor implicitly.
But i have added move because otherwise it not useful any way in real world problems.
Due to this you need to create object in place.
Using following code.
#include <iostream>
#include <map>
#include <memory>
struct A {
std::string name;
std::unique_ptr<int> p;
~A(){}
A(std::string n) : name(n) { }
A(A&& other): name(std::move(other.name)), p(std::move(other.p)){}
};
int main(int , char *[]){
std::map<int, A> m;
m.emplace(1, "Name");
for(const auto& e: m)
cout<< e.first<< ", "<< e.second.name<<'\n';
}
output: 1, Name
This is my tmp.hpp:
#include <cstdlib>
#include <utility>
#include <unordered_map>
using namespace std;
struct int_int_hasher {
size_t operator()(pair<int, int> const& p) const {
return static_cast<size_t>(p.first) << 32 | p.second;
}
};
template<class T, class H>
class BiBag {
unordered_map<T, uint, H> t_to_id_;
};
And simple tmp.cpp:
#include "tmp.hpp"
class tmp {
BiBag<pair<int, int>, int_int_hasher> tt =
BiBag<std::pair<int, int>, int_int_hasher>();
};
The error message is beyond my understanding:
g++ -std=c++11 -O2 tmp.cpp -lm -o tmp
tmp.cpp:6:32: error: expected ‘;’ at end of member declaration
BiBag<std::pair<int, int>, int_int_hasher>();
^
tmp.cpp:6:32: error: declaration of ‘BiBag<std::pair<int, int>, int_int_hasher> tmp::int_int_hasher’ [-fpermissive]
In file included from tmp.cpp:2:0:
tmp.hpp:7:8: error: changes meaning of ‘int_int_hasher’ from ‘struct int_int_hasher’ [-fpermissive]
struct int_int_hasher {
^
tmp.cpp:6:46: error: expected unqualified-id before ‘>’ token
BiBag<std::pair<int, int>, int_int_hasher>();
^
tmp.cpp:6:16: error: wrong number of template arguments (1, should be 2)
BiBag<std::pair<int, int>, int_int_hasher>();
^
If I remove the hasher from the picture and replace the map with a simple <int,int> map I get no error.
Thank you.
I've the following problem of which I cannot find a solution.
Of course, it could be that a solution does not exist at all, but I'd like to have a try on SO before to give up.
First of all, a snippet that compiles with no errors:
#include <unordered_set>
#include <memory>
struct S {
enum class E: unsigned int { FOO = 0, BAR };
};
namespace std
{
template<>
struct hash<S::E> {
using argument_type = S::E;
using underlying_type = std::underlying_type<argument_type>::type;
using result_type = std::size_t;
result_type operator()(argument_type const &s) const noexcept {
const underlying_type us = static_cast<underlying_type>(s);
hash<underlying_type> hfn;
return hfn(us);
}
};
}
int main() {
std::unordered_set<S::E> set;
}
With this code in mind, I found myself with the requirement of having the unordered_set as a data member of S or, at least, a derived class. A possible working solution is to add add the following lines once the std namespace has been closed:
struct D: public S {
std::unordered_set<S::E> set;
};
Another possible solution is maybe (I've not tried it) to use an unscoped enumeration. Anyway, the first attempt I made was to modify the definition of the struct S as it follows:
struct S {
enum class E: unsigned int { FOO = 0, BAR };
std::unordered_set<E> set;
};
This ends in an error because (if I've correctly understood the problem) the unordered_set requires the specialized hash function. Anyway, the latter requires S::E to be at least declared, thus it is not enough to swap the two pieces of code.
Here the first part of the error log (for it's very long):
In file included from /usr/include/c++/5/bits/hashtable.h:35:0,
from /usr/include/c++/5/unordered_set:47,
from main.cpp:1:
/usr/include/c++/5/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> >’:
/usr/include/c++/5/type_traits:137:12: required from ‘struct std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > >’
/usr/include/c++/5/type_traits:148:38: required from ‘struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > > >’
/usr/include/c++/5/bits/unordered_set.h:95:63: required from ‘class std::unordered_set<S::E>’
main.cpp:6:27: required from here
/usr/include/c++/5/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const std::hash<S::E>) (const S::E&)’
noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
^
In file included from /usr/include/c++/5/bits/move.h:57:0,
from /usr/include/c++/5/bits/stl_pair.h:59,
from /usr/include/c++/5/utility:70,
from /usr/include/c++/5/unordered_set:38,
from main.cpp:1:
/usr/include/c++/5/type_traits: In instantiation of ‘struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > > >’:
/usr/include/c++/5/bits/unordered_set.h:95:63: required from ‘class std::unordered_set<S::E>’
main.cpp:6:27: required from here
/usr/include/c++/5/type_traits:148:38: error: ‘value’ is not a member of ‘std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > >’
: public integral_constant<bool, !_Pp::value>
^
In file included from /usr/include/c++/5/unordered_set:48:0,
from main.cpp:1:
/usr/include/c++/5/bits/unordered_set.h: In instantiation of ‘class std::unordered_set<S::E>’:
main.cpp:6:27: required from here
/usr/include/c++/5/bits/unordered_set.h:95:63: error: ‘value’ is not a member of ‘std::__not_<std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > > >’
typedef __uset_hashtable<_Value, _Hash, _Pred, _Alloc> _Hashtable;
^
/usr/include/c++/5/bits/unordered_set.h:102:45: error: ‘value’ is not a member of ‘std::__not_<std::__and_<std::__is_fast_hash<std::hash<S::E> >, std::__detail::__is_noexcept_hash<S::E, std::hash<S::E> > > >’
typedef typename _Hashtable::key_type key_type;
Usually, in such a case, I can solve with something like a forward declaration, as the one in the example below:
struct B;
struct A { B *link; };
struct B { A *link; };
Unfortunately, I've not been able to do something similar with the enum embedded in a struct and that's why I started this question. Is it possible to solve it, thus avoid to define the derived class D, or deriving is the only viable solution in this case?
You can't forward declare a nested enum, see this answer.
You can do as ForEveR explained, or you can have your generic enum_hash template regardless of std namespace and use it in your data structure, since you are not forced to use std::hash as the hashing function, eg:
template<typename T>
struct enum_hash {
using argument_type = T;
using underlying_type = typename std::underlying_type<argument_type>::type;
using result_type = std::size_t;
result_type operator()(argument_type const &s) const noexcept {
const underlying_type us = static_cast<underlying_type>(s);
std::hash<underlying_type> hfn;
return hfn(us);
}
static_assert(std::is_enum<T>::value, "T must be an enum!");
};
struct S {
enum class E: unsigned int { FOO = 0, BAR };
std::unordered_set<S::E, enum_hash<S::E>> set;
};
You can just write specialization of hash for all enums and then all would work fine.
namespace std {
template<class E>class hash {
using sfinae = typename std::enable_if<std::is_enum<E>::value, E>::type;
public:
size_t operator()(const E&e) const {
return std::hash<typename std::underlying_type<E>::type>()(e);
}
};
};
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);
}
The code is below. The code does not compile on an online compiler, and I have no idea why. It is short and pretty self-explanatory, please look below for details.
#include <iostream>
#include <cmath>
using namespace std;
int N;
int distance(int a, int b){
if(abs(a-b) > N/2){
return N - abs(a-b);
}
return abs(a-b);
}
bool test(int x, int y){
if(distance(x,y) <=2){
return true;
}
return false;
}
int main()
{
N = 2;
cout << "Hello World" << endl;
cout << test(3,4) << endl;
return 0;
}
Error message below:
In file included from /usr/include/c++/4.8.3/bits/stl_algobase.h:65:0,
from /usr/include/c++/4.8.3/bits/char_traits.h:39,
from /usr/include/c++/4.8.3/ios:40,
from /usr/include/c++/4.8.3/ostream:38,
from /usr/include/c++/4.8.3/iostream:39,
from main.cpp:1:
/usr/include/c++/4.8.3/bits/stl_iterator_base_types.h: In instantiation of 'struct std::iterator_
traits<int>':
/usr/include/c++/4.8.3/bits/stl_iterator_base_funcs.h:114:5: required by substitution of 'templ
ate<class _InputIterator> typename std::iterator_traits<_Iterator>::difference_type std::distance
(_InputIterator, _InputIterator) [with _InputIterator = int]'
main.cpp:15:20: required from here
/usr/include/c++/4.8.3/bits/stl_iterator_base_types.h:165:53: error: 'int' is not a class, struct
, or union type
typedef typename _Iterator::iterator_category iterator_category;
^
/usr/include/c++/4.8.3/bits/stl_iterator_base_types.h:166:53: error: 'int' is not a class, struct
, or union type
typedef typename _Iterator::value_type value_type;
^
/usr/include/c++/4.8.3/bits/stl_iterator_base_types.h:167:53: error: 'int' is not a class, struct
, or union type
typedef typename _Iterator::difference_type difference_type;
^
/usr/include/c++/4.8.3/bits/stl_iterator_base_types.h:168:53: error: 'int' is not a class, struct
, or union type
typedef typename _Iterator::pointer pointer;
^
/usr/include/c++/4.8.3/bits/stl_iterator_base_types.h:169:53: error: 'int' is not a class, struct
, or union type
typedef typename _Iterator::reference reference;
using namespace std;
This is a bad idea; it dumps anything that's been declared in the std namespace into the global namespace, where it might conflict with anything you declare in the global namespace.
int distance(int a, int b)
This declares a function in the global namespace that conflicts with a function template of the same name in the std namespace.
if(distance(x,y) <=2)
The std::distance template is a better match than your function, according to the arcane rules of overload resolution. Trying to instantiate that, it fails since it can only be instantiated for iterator types, not int.
The best option is to remove the rogue using-directive, and add std:: to anything you use from the standard library. If you don't want to do that for some reason, then qualify your function call to specify the one declared in the global namespace:
if(::distance(x,y) <=2)