Search code examples
c++c++17member-functionsfunction-templates

Which member functions can be templated in C++?


I was asked a question

Which class functions can be templated in C++? (constructor, destructor, const, static)

Did I understand correctly that all member functions (except destructor) can be templated?

Constructor / destructor

class A {
public:
    template<class T>
    A(T t) {
        cout << t << endl; 
    }

    /*
    template<class U>
    ~A() {  // error: destructor cannot be declared as a template
        cout << "Destructor\n";
    }*/

};


int main() {
    A a(5);
}

Static function

Yes, it can be template.

class A {
public:
    template< typename T>
    static double foo( vector<T> arr );

};

template< typename T>
double A::foo( vector<T> arr ){ cout << arr[0] << endl; }

int main() {
    A a;
    A::foo<int>({1, 2, 3});
}

Non-constant / constant member function

Yes.

class A {
public:
    template< typename T>
    double foo( vector<T> arr ) const {
        cout << arr[0] << endl;
    }
};

int main() {
    A a;
    a.foo<int>({1, 2, 3});
}

Solution

  • Technically, any member function can be templated, since that term includes member functions of class templates (or of member classes of class templates, or local classes in function templates, etc.) that can of course use the template parameters for whatever enclosing template. The real question is which members can be function templates (and thus not functions at all).

    The answer is simple: any member function that is not a (prospective) destructor and not virtual can instead be a function template. (Constructor templates and conversion function templates can’t be invoked with explicit template arguments, so those have to be deduced.)

    Note, though, that neither a function template nor a specialization of one can count as certain special member functions, even if it can be used in their stead (thanks to suppressing the implicit declaration or being a better match):

    struct A {
      template<class=int>
      A(int=0);          // #1, not a default constructor
      template<class T>
      A(T&);             // #2, not a copy constructor
      template<class T>
      A& operator=(T&);  // #3, not a copy-assignment operator
    } a,         // calls #1
      b(a),      // calls #2
      &r=(a=b);  // calls #3
    

    A still has defaulted copy/move operations here because none of these interfere.