I'm very surprised to find that the following compiles:
#include <iostream>
using namespace std;
template<typename T>
class So开发者_如何学PythonmeCls {
public:
void UseT(T t) {
cout << "UseT" << endl;
}
};
template<>
class SomeCls<int> {
// No UseT? WTF?!??!?!
};
int main(int argc, char * argv[]) {
SomeCls<double> d;
SomeCls<int> i;
d.UseT(3.14);
// Uncommenting the next line makes this program uncompilable.
// i.UseT(100);
return 0;
}
Why is this allowed? It just seems wrong that class SomeCls<int>
doesn't need to have a void UseT(T t)
method. I'm sure I'm missing the point of specialization here (I'm not a C++ expert). Can someone please enlighten me?
Because SomeCls<double>
is a completely different type than SomeCls<int>
or any other SomeCls<T>
. They are not related in any way, so they can have whatever members they want. Just be sure not to call i.UseT()
, this is where the compiler would start to complain, of course.
Specialisation can specialise in any way you see fit. If you want to omit all the methods, add or remove base classes, add or remove data members then that's fine.
template <class T>
class Foo {};
template <>
class Foo<int> { void extrafunc(); }; //fine
template <>
class Foo<bool> : public ExtraBase {}; // fine
template <>
class Foo<double> { int extradata; }; // fine
When specialising functions, the only restriction is that the arguments stay the same (with respect to the primary template), although you can overload to your heart's content.
template <class T>
void foo(const T&);
template <>
void foo<int>(int); // not fine, must be const int&
void foo(int); // fine, this is an overload, not a specialisation
template <class T>
void foo(T*); // fine, again this is an overload, not a specialisation
Your code never calls the int
version of UseT, so you don't need to provide it.
I've marked an answer as "correct", but I'm not really satisfied. I'm not asking HOW it works; I'm asking why it was designed that way. The way it works doesn't strike me as consistent with OO. It does even seem consistent. Why does function template specialization have the restriction that the interface must be consistent, while class template specialization does not??
If that was your question, you probably should have said so to begin with.
I'm going to start with the last bit: why functions require identical signatures. That ones easy, functions already have a way to reuse names via overloading.
int f(int);
double f(double); //no templates needed
Allowing a specialization to change the function's signature would needlessly complicate the already difficult process of name resolution, without actually providing any additional functionality.
In the case of class types, a template is much more complicated. Not only do you have member functions to consider, you have member objects, typedefs, nested types, and so on. Specialization specializes all of those. If SomeTemplatedObject<double>
requires a particular private member that SomeTemplatedObject<T>
in general doesn't, how can you specialize SomeTemplatedObject
for double
without changing the "interface"? Or what of methods that don't make sense for certain types? Or nested types that need to be modified in order to keep a consistent interface? And that's not even touching on the larger issue of template metaprogramming.
You don't even need to have a complete type for the general case.
template<typename T>
struct Object;
template<>
struct Object<int> { //what interface does this need?
typedef int type;
};
If you feel compelled to adhere to some purist definition of OO, then you are always free to just not specialize templates without precisely matching their original layout.
精彩评论