4

While programming with the auto keyword it would sometimes be convenient to know the type that is used by the compiler at compile time. It does not matter if the compilation aborts where I need to know the type. Simple example:

std::vector< int > s{1, 2, 3}; 

for (auto elem : s) {
    elem = 5;
}   

for (auto elem : s) {
    std::cout << elem << std::endl;
}   

will print

1
2
3

because elem is of type int, not int&. It would be nice to try compile the code and get the type of elem to catch such mistakes early.

Barry
  • 286,269
  • 29
  • 621
  • 977
hochl
  • 12,524
  • 10
  • 53
  • 87
  • Not sure what you're asking. Any code that you would write to ensure that `elem` is a reference seems quite a bit longer than having written `auto&& elem` to begin with. – Barry Sep 22 '16 at 09:05
  • 3
    You could use [`std::is_reference`](http://en.cppreference.com/w/cpp/types/is_reference) together with [`static_assert`](http://en.cppreference.com/w/cpp/language/static_assert). But it adding that to every loop is more work than just making sure that you use the correct type to begin with. And no, there's no way of making the compiler do the check for you, as the assignment is not invalid in any way. – Some programmer dude Sep 22 '16 at 09:05
  • 2
    Your example looks like a good reason for a compiler warning. For example, my compiler says `warning: variable ‘elem’ set but not used`. – Sergey Sep 22 '16 at 09:14
  • It would be nice to have a generic method to show the type, this is just a very simple example where it could be helpful. – hochl Sep 22 '16 at 09:30
  • 1
    IIRC, `auto` is never a reference type. Are you expecting the compiler to deduce that you intended to use a reference from the existence of the assignment and warn you? – molbdnilo Sep 22 '16 at 09:43
  • 1
    `expression_name`: http://stackoverflow.com/a/20721887/576911 – Howard Hinnant Sep 22 '16 at 14:45

2 Answers2

14

Classical way is to declare template structure without definition:

template <typename> struct Debug;

and then use it:

template struct Debug<std::string>;

or

for (auto elem : s) {
    Debug<decltype(elem)>{};

    elem = 5;
}

Message error looks like

error: explicit instantiation of 'struct Debug<std::__cxx11::basic_string<char> >' before definition of template
 template struct Debug<std::string>;
                 ^~~~~~~~~~~~~~~~~~

error: invalid use of incomplete type 'struct Debug<int>'
         Debug<decltype(e)>{};

Demo

BTW, now some IDEs show the type when mouse is over auto or the variable.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Great! I like this even better -- unfortunately I could not find this type of solution with my Google-foo :( – hochl Sep 22 '16 at 11:31
2

Actually I just found an answer to my own question:

template<typename T>
void show_type_abort_helper()
{
    return __PRETTY_FUNCTION__;
}

#define show_type_abort(x) show_type_abort_helper< decltype(x) >()

Usage:

std::vector< int > s{1, 2, 3};

for (auto elem : s) {
    show_type_abort(elem);
    elem = 5;
}

Produces the following error message with g++ (version 6.1.1):

$ g++ test.cpp
test.cpp: In instantiation of ‘void show_type_abort_helper() [with T = int]’:
                                                                       ^^^
test.cpp:17:9:   required from here
test.cpp:7:12: error: return-statement with a value, in function returning 'void' [-fpermissive]
    return __PRETTY_FUNCTION__;

Check the output at T = int to see the compiler uses int as type. This seems to work with clang as well:

$ clang++-3.8 -std=c++11 test.cpp
test.cpp:7:5: error: void function 'show_type_abort_helper' should not return a value [-Wreturn-type]
    return __PRETTY_FUNCTION__;
    ^      ~~~~~~~~~~~~~~~~~~~
test.cpp:17:9: note: in instantiation of function template specialization 'show_type_abort_helper<int>' requested here
                                                                                                  ^^^
        show_type_abort(elem);

Changing to for (const auto& elem : s) gives

with T = const int&
         ^^^^^^^^^^

or

show_type_abort_helper<const int &>
                       ^^^^^^^^^^^

So it seems I can find out the type at compile time and abort. This just came in handy for a very complex type that consisted of several typedefs and template parameters where I just could not see what was going on.

hochl
  • 12,524
  • 10
  • 53
  • 87