I'm reading Meyers' book on modern c++, where I find a code snippet might be useful:
template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&) [N]) noexcept {
return N;
}
This function deduces N for us as a compile-time constant. So I want to apply it in my code:
template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&) [N]) noexcept {
return N;
}
template <typename T>
class A {
public:
const static char* names[];
};
template<typename T>
const char* A<T>::names[] = {"foo", "bar"};
template<>
const char* A<bool>::names[] = {"foo","bar", "foobar"};
If put in one file it works perfectly fine, arraySize(A<int>::names) is 2 and arraySize(A<bool>::names) is 3.
But when used in larger project requiring separate .h and .cpp, the problem comes:
If put the declaration of the specified version of
A<bool>::names[]in a.cpp, the code compiles(and links) but the compiler can't see it when deducingarraySize(), soarraySize(A<bool>::names)is deduced to2.If put the declaration of
A<bool>::names[]in a.h, of course, we get a "duplicate symbol" link error.
So how can I make arraySize(A<bool>::names) correctly deduced to 3?
You can't have class templates use a .cpp file, it simply doesn't work with how compilers work. What the compiler does is make a version for every time you send a new data type to the class.
So basically if you have a class template that takes one variable, and you make two object, one with an int, and one with a string, of the class type, the compiler will make two definitions of the class. The problem is that the compiler doesn't know to do this with the .cpp also. I heard that you can rename the .cpp to anything else, like .tpp, or manually overload the class definition. Both ways are kinda hacky, and everyone just writes template classes in the .h file, which might seem none uniform from other classes, but it is just how it is.