开发者

Why don't I have to define the same members when I do total specialization of a class template in C++?

开发者 https://www.devze.com 2023-03-13 00:27 出处:网络
I\'m very surprised to find that the following compiles: #include <iostream> using namespace std;

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 intversion 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消