0

can someone please shed some light on a curious phenomenon with C++ templates. Consider this simple code:

class B {};

template <typename T>
class A 
{
    T _v;
public:
    A() {}
    void add(T a) { _v += a; }
};

int main()
{
    A<B> b;
    return 0;
}

Clearly this isn't legal because the += operator is not defined for class B, and therefore the code inside the add method is invalid. Yet this code compiles fine!

It is not until you call the add method that you get a compile error:

int main()
{
    A<B> b;
    b.add(B()); // complains about a missing += operator
    return 0;
}

For a non-template class the compile error occurs regardless of whether the class is used at all.

class C
{
    B _v;
public:
    C() {}
    void add(B a) { _v += a; } // compile error here right away
};

Why is that? Thanks.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
O.T.Vinta
  • 217
  • 1
  • 4
  • Template members are not instanciated until ODR used. If you don't call the `add` function, it won't be instanciated, and no errors occur. – Red.Wave Aug 15 '23 at 20:13
  • 1
    @Red.Wave "instanciated" is not a word (in English, or in C++ nomenclature). The word you are misspelling is instan*t*iated – Peter Aug 16 '23 at 01:52
  • @Peter Never been good at spelling. That's why I became CTRL+V guy – Red.Wave Aug 16 '23 at 18:42

1 Answers1

4

If a member function of a class template is not used it is not instantiated.

In the second program the member functon of the class template A is used and the compiler tries to instantiate it. As a result it issues an error.

From the C++20 Standard (13.9.2 Implicit instantiation)

3 The implicit instantiation of a class template specialization causes

(3.1) — the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and

(3.2) — the implicit instantiation of the definitions of deleted member functions, unscoped member enumerations, and member anonymous unions.

And there is an example

[Example 3 :

template<class T>
struct C {
    void f() { T x; }
    void g() = delete;
};
C<void> c; // OK, definition of C<void>::f is not instantiated at this point
template<> void C<int>::g() { } // error: redefinition of C<int>::g

— end example]

Such an approach allows to reduce the compilation time. You don't pay for what you don't use.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335