2

I just started to understand some template basics. Actually, until now I just accepted it as a fact, but I dont really understand the reason why this is broken:

template <typename T,bool hasFoo>
struct Broken {
    void foobar(){
        if (hasFoo){T::foo();}
        else { std::cout << "BROKEN" << std::endl;}
    }
};

int main(){
    Broken<int,false> t;
    t.foobar();
}

while this works:

template <typename T>
struct Works {
    void foo(){T::foo();}
    void bar(){std::cout << "WORKS" << std::endl;}
};

int main(){
    Works<int> t;
    t.bar();
}

Somehow it is obvious, but I just want to make sure that I am not missing something: Does this work, because if the function Works<int>::foo() is never called, it simply does not get instantiated?

PS: To avoid misunderstandings: I know, why Broken is broken and I recently had a question related to this where I got good answers, however after that I thought that also Works<int> should not compile until I accidentally passed a "wrong" template parameter and was surprised that it did compile.

Community
  • 1
  • 1
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185

2 Answers2

8

if the function Works::foo() is never called, it simply does not get instantiated?

Yes, a non-virtual member function of class template won't be instantiated until it's required.

From the standard, §12.8.1/10 Implicit instantiation [temp.inst]:

(emphasis mine)

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 ([stmt.if]), unless such instantiation is required.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Thats exactly what i was looking for. Maybe you can suggest a better title, because atm the question is pretty useless for anybody but me. – 463035818_is_not_an_ai Nov 11 '15 at 10:20
  • Good one... I couldn't really come up with anything shorter than "Invalid method is not instantiated in a templated class, but boolean template parameter in instantiated method fails at compile-time.". – CompuChip Nov 11 '15 at 10:28
  • " being used." is a poor phrase. explicit instantiation doesn't "use" it by common meaning of the word (hence the standard saying "require instantiation" not "used") – xaxxon Aug 11 '18 at 20:50
1

To answer the question in your title, no, it does not need to be called to be instantiated.

This code does not compile, yet foo is never called.

template <typename T>
struct Works {
    void foo(){T::foo();}
    void bar(){}
};

// this requires foo being instantiated because it may be called from
// elsewhere - the compiler cannot know.
template Works<int>; 

int main(){
    Works<int> t;
    t.bar();
}

live: https://godbolt.org/g/u4frVZ

This is why the standard says it is not instantiated unless it requires instantiation and the rules for that are more complicated than whether it is called.

xaxxon
  • 19,189
  • 5
  • 50
  • 80