Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Getting type of Class inside a Class Method

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

>Solution :

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);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading