Search code examples
c++templates

Extern specialization of some methods (not all) and keeping the class generic, is it possible?


I have this class : (common.h)

template <typename T>
class A{
public:
  A();
  int a(){
    return 42;
  }
  int b(){
    return 43;
  }
};

Let's say it's A<int> and A<char> are both instantiated in main.cpp

Is it possible to declare an (extern) specialized A<int>::a() that is defined in another file (a.cpp), while keeping everything else generic ?

Bonus : is it possible (in addition) to specialized A<int>::b() defined in yet another file (b.cpp)?

(The bonus question is more about to know if a compiler can emit only some method in the .o or if it should always emit the full specialized class)

By the way, I don't have any use case in mind, it's only to improve my knowledge about templates


Solution

  • Is it possible to declare an (extern) specialized A::a() that is defined in another file (a.cpp), while keeping everything else generic ?

    Yes this is possible because explicit specialization(whether declaration or definition) behaves like non-template(declaration/definition) in this regard.

    Below is a working example as per your given requirements:

    common.h

    #pragma once 
    #include <iostream>
    
    template <typename T>
    class A{
    public:
      A()=default;
      int a(){
        std::cout << "generic version of a\n";
        return 42;
      }
      int b(){
        std::cout << "generic version of b\n";
        return 43;
      }
      void c()
      {
          std::cout << "generic version of c\n";
      }
    };
    
    //declarations for specialization
    template <> int A<int>::a();   //a is specialized for int(say) 
    template <> int A<int>::b();  //b is specialized for int(say)
    

    a.cpp

    #include "common.h"
    //definition
    template <> int A<int>::a()
    {
        std::cout << "specialized int version of a\n";
        return 100;
    }
    

    b.cpp

    #include "common.h"
    //definition
    template <> int A<int>::b()
    {
        std::cout << "specialized int version of b\n";
        return 101;
    }
    

    main.cpp

    
    #include <iostream>
    #include "common.h"
    
    
    int main() {
       A<int> a1;
       a1.a();         // uses specialized int version of a 
       a1.b();         // uses specialized int version of b 
       a1.c();         //uses generic version of c
       
       A<char> a2;
       a2.a();        //uses generic version of a
       a2.b();        //uses generic version of b 
       
    }