I want to determine the type of this
variable inside a class method.
For example, take the following example -
#include <iostream>
#include <cstdlib>
#include <map>
class Base{
};
using getPrintString = std::map<Base, std::string>;
class A : public Base{
public:
void print(getPrintString& stringMap){
std::string toPrint = stringMap[std::remove_reference<decltype(*this)>::type];
std::cout<<toPrint<<std::endl;
}
};
class B: public Base{
public:
void print(getPrintString& stringMap){
std::string toPrint = stringMap.at(std::remove_reference<decltype(*this)>::type);
std::cout<<toPrint<<std::endl;
}
};
getPrintString stringMap{
{std::declval<A>(), "A String"},
{std::declval<B>(), "B String"}
};
int main()
{
A a;
B b;
a.print(stringMap);
b.print(stringMap);
}
In the above code, I want to decide what to print, depending on which class is calling the print
method. I thought the class type of the method can be ascertained using decltype(*this)
. as for any Class type X
, this
will be a pointer of type X*
, followed by std::remove_reference
, as I am using decltype
on a variable.
However, upon compilation, I run into the following error -
test.cpp: In member function ‘void A::print(getPrintString&)’:
test.cpp:15:85: error: expected primary-expression before ‘]’ token
15 | std::string toPrint = stringMap[std::remove_reference<decltype(*this)>::type];
| ^
test.cpp: In member function ‘void B::print(getPrintString&)’:
test.cpp:23:88: error: expected primary-expression before ‘)’ token
23 | std::string toPrint = stringMap.at(std::remove_reference<decltype(*this)>::type);
| ^
In file included from /usr/include/c /11/bits/move.h:57,
from /usr/include/c /11/bits/exception_ptr.h:43,
from /usr/include/c /11/exception:153,
from /usr/include/c /11/ios:39,
from /usr/include/c /11/ostream:38,
from /usr/include/c /11/iostream:39,
from test.cpp:1:
/usr/include/c /11/type_traits: In instantiation of ‘decltype (__declval<_Tp>(0)) std::declval() [with _Tp = A; decltype (__declval<_Tp>(0)) = A&&]’:
test.cpp:29:21: required from here
/usr/include/c /11/type_traits:2366:47: error: static assertion failed: declval() must not be used!
2366 | static_assert(__declval_protector<_Tp>::__stop,
| ^~~~~~
/usr/include/c /11/type_traits:2366:47: note: ‘std::__declval_protector<A>::__stop’ evaluates to false
/usr/include/c /11/type_traits: In instantiation of ‘decltype (__declval<_Tp>(0)) std::declval() [with _Tp = B; decltype (__declval<_Tp>(0)) = B&&]’:
test.cpp:30:21: required from here
/usr/include/c /11/type_traits:2366:47: error: static assertion failed: declval() must not be used!
/usr/include/c /11/type_traits:2366:47: note: ‘std::__declval_protector<B>::__stop’ evaluates to false
In file included from /usr/include/c /11/string:48,
from /usr/include/c /11/bits/locale_classes.h:40,
from /usr/include/c /11/bits/ios_base.h:41,
from /usr/include/c /11/ios:42,
from /usr/include/c /11/ostream:38,
from /usr/include/c /11/iostream:39,
from test.cpp:1:
/usr/include/c /11/bits/stl_function.h: In instantiation of ‘constexpr bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Base]’:
/usr/include/c /11/bits/stl_tree.h:2174:33: required from ‘std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_hint_unique_pos(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, const key_type&) [with _Key = Base; _Val = std::pair<const Base, std::__cxx11::basic_string<char> >; _KeyOfValue = std::_Select1st<std::pair<const Base, std::__cxx11::basic_string<char> > >; _Compare = std::less<Base>; _Alloc = std::allocator<std::pair<const Base, std::__cxx11::basic_string<char> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree<Base, std::pair<const Base, std::__cxx11::basic_string<char> >, std::_Select1st<std::pair<const Base, std::__cxx11::basic_string<char> > >, std::less<Base>, std::allocator<std::pair<const Base, std::__cxx11::basic_string<char> > > >::const_iterator; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::key_type = Base]’
/usr/include/c /11/bits/stl_tree.h:2234:4: required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique_(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, _Arg&&, _NodeGen&) [with _Arg = const std::pair<const Base, std::__cxx11::basic_string<char> >&; _NodeGen = std::_Rb_tree<Base, std::pair<const Base, std::__cxx11::basic_string<char> >, std::_Select1st<std::pair<const Base, std::__cxx11::basic_string<char> > >, std::less<Base>, std::allocator<std::pair<const Base, std::__cxx11::basic_string<char> > > >::_Alloc_node; _Key = Base; _Val = std::pair<const Base, std::__cxx11::basic_string<char> >; _KeyOfValue = std::_Select1st<std::pair<const Base, std::__cxx11::basic_string<char> > >; _Compare = std::less<Base>; _Alloc = std::allocator<std::pair<const Base, std::__cxx11::basic_string<char> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree<Base, std::pair<const Base, std::__cxx11::basic_string<char> >, std::_Select1st<std::pair<const Base, std::__cxx11::basic_string<char> > >, std::less<Base>, std::allocator<std::pair<const Base, std::__cxx11::basic_string<char> > > >::iterator; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree<Base, std::pair<const Base, std::__cxx11::basic_string<char> >, std::_Select1st<std::pair<const Base, std::__cxx11::basic_string<char> > >, std::less<Base>, std::allocator<std::pair<const Base, std::__cxx11::basic_string<char> > > >::const_iterator]’
/usr/include/c /11/bits/stl_tree.h:1102:23: required from ‘std::__enable_if_t<std::is_same<_Val, typename std::iterator_traits<_InputIterator>::value_type>::value> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_range_unique(_InputIterator, _InputIterator) [with _InputIterator = const std::pair<const Base, std::__cxx11::basic_string<char> >*; _Key = Base; _Val = std::pair<const Base, std::__cxx11::basic_string<char> >; _KeyOfValue = std::_Select1st<std::pair<const Base, std::__cxx11::basic_string<char> > >; _Compare = std::less<Base>; _Alloc = std::allocator<std::pair<const Base, std::__cxx11::basic_string<char> > >; std::__enable_if_t<std::is_same<_Val, typename std::iterator_traits<_InputIterator>::value_type>::value> = void; typename std::iterator_traits<_InputIterator>::value_type = std::pair<const Base, std::__cxx11::basic_string<char> >]’
/usr/include/c /11/bits/stl_map.h:232:36: required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::map(std::initializer_list<std::pair<const _Key, _Tp> >, const _Compare&, const allocator_type&) [with _Key = Base; _Tp = std::__cxx11::basic_string<char>; _Compare = std::less<Base>; _Alloc = std::allocator<std::pair<const Base, std::__cxx11::basic_string<char> > >; std::map<_Key, _Tp, _Compare, _Alloc>::allocator_type = std::allocator<std::pair<const Base, std::__cxx11::basic_string<char> > >]’
test.cpp:31:1: required from here
/usr/include/c /11/bits/stl_function.h:400:20: error: no match for ‘operator<’ (operand types are ‘const Base’ and ‘const Base’)
400 | { return __x < __y; }
Filtering out, there are two main error - first
test.cpp: In member function ‘void A::print(getPrintString&)’:
test.cpp:15:85: error: expected primary-expression before ‘]’ token
15 | std::string toPrint = stringMap[std::remove_reference<decltype(*this)>::type];
| ^
test.cpp: In member function ‘void B::print(getPrintString&)’:
test.cpp:23:88: error: expected primary-expression before ‘)’ token
23 | std::string toPrint = stringMap.at(std::remove_reference<decltype(*this)>::type);
|
Which comes from the use of decltype
. How to use decltype
correctly in this context.
Second, there is an another internal error using declval
, what am I doing wrong and how to fix it ?
TIA
CodePudding user response:
If you want to build a map of types, you need to use typeid
to get the type_info
and then use its type_index
(or hash value) as Key in the map.
Example:
#include <cstdlib>
#include <iostream>
#include <map>
#include <typeindex>
#include <typeinfo>
class Base {
public:
virtual ~Base() = default;
};
using getPrintString = std::map<std::type_index, std::string>;
class A : public Base {
public:
void print(getPrintString& stringMap) {
std::string toPrint = stringMap[std::type_index(typeid(decltype(*this)))];
std::cout << toPrint << std::endl;
}
};
class B : public Base {
public:
void print(getPrintString& stringMap) {
std::string toPrint = stringMap[std::type_index(typeid(decltype(*this)))];
std::cout << toPrint << std::endl;
}
};
int main() {
getPrintString stringMap{{std::type_index(typeid(A)), "A String"},
{std::type_index(typeid(B)), "B String"}};
A a;
B b;
a.print(stringMap);
b.print(stringMap);
}