I'm learning C++ and I'm sort of baffled by how its templates work. Let me give you an example, this works:
#include <iostream>
#include <cstdlib>
#include <type_traits>
template <class T> const T first(const T& first, const T& second) {
return first.size()<second.size() ? first : second;
}
int main(int argc, char** argv) {
std::string x = "the short string";
std::string y = "the longer string";
std::cout << "first of x, y is "<<first(y,x)<<std::endl;
}
the above code works, but what is to stop me from using an integer as my template parameter?
int main(int argc, char** argv) {
int x = 3;
int y = 8;
std::cout << "first of x, y is "<<first(y,x)<<std::endl;
}
making the change above gives you a compilation error in the "first" method, not the "main" method. I read here that I can use the static_assert statement to handle this problem, but I can't figure out how to check that the type T is a basic_string or subclass at compilation time.
I wanted to know if C++ will report the problem in the right place when I use static_assert, so I switched the problem around like so:
template <class T> const T first_numeric(const T& first, const T& second) {
static_assert(std::is_arithmetic<T>::value,"You must use a number!");
return first<second ? first : second;
}
int main(int argc, char** argv) {
// int x = 3;
// int y = 8;
// std::cout << "first_numeric of x, y is "<<first_numeric(y,x)<<std::endl;
std::string x = "3";
std::string y = "8";
std::cout << "first_numeric of x, y is "<<first_numeric(y,x)<<std::endl;
}
If I had started this question with the above example, I inevitably would have been told "why on earth would you want to restrict the type parameter?" Hopefully you understand now.
In the example above, the compiler does fail like we want it to, but it fails on the wrong line. It shows the compilation error on the static_assert line, not the line where I call the method with illegal arguments.
You're probably thinking, "so what?" Well it's obvious in this example where the problem is, but it might not be when you have 10000 lines of code. Sure you can use the IDE to get a call hierarchy on that function, but if there are hundreds of places where that method is getting called, you would be checking each and every one of them just to find your mistake.
So my questions are:
- Is there any way to have C++ report the compilation error on the line where the method was called with illegal type parameters?
- If not, what guidance can you give me to avoid this problem or work around it?
===============================
Update: this is the error output
mkdir -p build/Debug/GNU-Linux-x86
rm -f "build/Debug/GNU-Linux-x86/main.o.d"
g++ -c -g -std=c++11 -MMD -MP -MF "build/Debug/GNU-Linux-x86/main.o.d" -o build/Debug/GNU-Linux-x86/main.o main.cpp
main.cpp: In instantiation of ‘const T first_numeric(const T&, const T&) [with T = std::basic_string<char>]’:
main.cpp:22:64: required from here
main.cpp:6:5: error: static assertion failed: You must use a number!
static_assert(std::is_arithmetic<T>::value,"You must use a number!");
^
make[2]: *** [build/Debug/GNU-Linux-x86/main.o] Error 1
make[2]: Leaving directory `/home/mike/NetBeansProjects/CppApplication_1'
make[1]: *** [.build-conf] Error 2
make[1]: Leaving directory `/home/mike/NetBeansProjects/CppApplication_1'
make: *** [.build-impl] Error 2
BUILD FAILED (exit value 2, total time: 460ms)
apparently the output did mention line 22 where the real problem was, but it did not highlight it in the source code. I should have read the output instead of just looking at what was highlighted.