You can try to throw an error in the template with this expression as an argument, and the compiler error message will be of the type you are looking for.
For example, using GCC:
#include <map> #include <string> template<typename T> void ErrorType(T &t) { char x[sizeof(t)==0 ? 1 : -1]; } template<typename T> void ErrorType(const T &t) { char x[sizeof(t)==0 ? 1 : -1]; } int main() { double d = 3; const double cd = 3; ErrorType(d); ErrorType(cd); ErrorType(3); std::map<std::string, int> x; ErrorType(x.begin()); } $ g++ -c test.cpp test.cpp: In function 'void ErrorType(T&) [with T = double]': test.cpp:17:20: instantiated from here test.cpp:6:14: error: size of array is negative test.cpp: In function 'void ErrorType(const T&) [with T = double]': test.cpp:18:21: instantiated from here test.cpp:10:14: error: size of array is negative test.cpp: In function 'void ErrorType(const T&) [with T = int]': test.cpp:19:20: instantiated from here test.cpp:10:14: error: size of array is negative test.cpp: In function 'void ErrorType(const T&) [with T = std::_Rb_tree_iterator<std::pair<const std::basic_string<char>, int> >]': test.cpp:22:28: instantiated from here test.cpp:10:14: error: size of array is negative
Thus, the types are reset double , int and std::_Rb_tree_iterator<std::pair<const std::basic_string<char>, int> > . The first overload is not constant, which means that the expression is a non-constant l-value.
The trick sizeof(t)==0 necessary so that the whole expression depends on the template parameter and delays the error until an instance is created. The error itself (the size of the array is negative), of course, is meaningless.
And if you use C ++ 11, you can improve:
#include <map> #include <string> template<typename T> void ErrorType(T &&t) { static_assert(sizeof(t)==0, "Reporting type name"); } int main() { double d = 3; const double cd = 3; ErrorType(d); ErrorType(cd); ErrorType(3); std::map<std::string, int> x; ErrorType(x.begin()); } $ g++ -c test.cpp -std=gnu++0x test.cpp: In function 'void ErrorType(T&&) [with T = double&]': test.cpp:15:20: instantiated from here test.cpp:6:9: error: static assertion failed: "Reporting type name" test.cpp: In function 'void ErrorType(T&&) [with T = const double&]': test.cpp:16:21: instantiated from here test.cpp:6:9: error: static assertion failed: "Reporting type name" test.cpp: In function 'void ErrorType(T&&) [with T = int]': test.cpp:17:20: instantiated from here test.cpp:6:9: error: static assertion failed: "Reporting type name" test.cpp: In function 'void ErrorType(T&&) [with T = std::_Rb_tree_iterator<std::pair<const std::basic_string<char>, int> >]': test.cpp:20:28: instantiated from here test.cpp:6:9: error: static assertion failed: "Reporting type name"
As an added bonus, this can make the difference between constants l-values and r-values. The first is the value of double l, the second is a const double l, and the other two are the values of r.
source share