11

I came across with the following program in C++:

template <class T>
class Val {
protected:
    T x0, x;
public:
    Val(T t = 1) : x0(t), x(1) {}
    T val() { return x; }
    void promote() { this->promote_value(); }
};

For some reason Val<int>(4).val(); works fine even though there is no method promote_value(). I tried to remove the templates:

class OtherVal {
protected:
    int x0, x;
public:
    OtherVal (int t = 1) : x0(t), x(1) {}
    int val() { return x; }
    void promote() { this->promote_value(); }
};

But now I get an error:

error: ‘class OtherVal’ has no member named ‘promote_value’; did you mean ‘promote’?

Why does C++ behave like this?

user7610
  • 25,267
  • 15
  • 124
  • 150
vesii
  • 2,760
  • 4
  • 25
  • 71

2 Answers2

13

Template class methods are not instantiated until they are used. Once you try calling promote() or even get its address like this &Val<int>::promote then you'll get an error.

From the C++ standard:

§ 17.8.1.10 An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, a static data member of a class template, or a substatement of a constexpr if statement (9.4.1), unless such instantiation is required.

alter_igel
  • 6,899
  • 3
  • 21
  • 40
r3mus n0x
  • 5,954
  • 1
  • 13
  • 34
  • Thank you. Are there any checks at all that the compiler does on `promote()`? I guess syntax errors. – vesii Jul 04 '19 at 16:28
  • @vesil, AFAIK the compiler is obligated by the standard to parse the non-instantiated method definition and check it for correctness as much as it can without knowing the `T`. However the MSVC is known for violating that requirement and not bothering to check anything thus allowing a complete nonsense in method definition which will only be discovered when the method is actually used. – r3mus n0x Jul 04 '19 at 16:34
  • So if the method `promote()` is virtual it will fail in compilation? – vesii Jul 04 '19 at 21:12
  • @vesii, yes, actually it will, because making it virtual will make the compiler **implicitly take its address** in order to put it into a virtual table. – r3mus n0x Jul 05 '19 at 05:41
9

Templates have always worked this way, principally to facilitate their use.

Because Val<int>(4).val(); doesn't call promote, that function is not compiled for your particular instantiation of that template so the compiler does not issue a diagnostic.

Many metaprogramming techniques depend on this behaviour.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483