10

I am using VS Express 2013 trying to compile a c++ project. I've created a template class with some functions. The class and its functions are all in one header file. I've included the file, I've used the class, I've called functions from it, and despite all that visual studio won't compile the classes' functions that I'm not using. I've turned off all optimizations. Do I HAVE to use a function that I've written just to see that it compiles or not?

Here is the function:

void remove(ID id)
{
    sdfgsdfg456456456456sfdsdf
}

The function shouldn't compile. And indeed the project won't compile if I do use this function, but if I don't use the function the project will compile, even if I use other functions from within this class.

Is there a fix to this? Will the same thing happen if I implement the function in a .cpp file?

Edit: I neglected to mention it is a template class. I've added that information in.

Constructor
  • 7,273
  • 2
  • 24
  • 66
user1594138
  • 1,003
  • 3
  • 11
  • 20
  • Do you compile in debug configuration, or in release configuration? – Sergey Kalinichenko May 15 '14 at 13:25
  • In release configuration. – user1594138 May 15 '14 at 13:25
  • Does the same thing happen when you compile in debug configuration? – Sergey Kalinichenko May 15 '14 at 13:25
  • This is an optimization BTW, think about it the compiler produces neater code if it removes unused references. – 101010 May 15 '14 at 13:26
  • @40two - And that's why I disabled optimizations. Maybe this kind of optimization isn't included in that. – user1594138 May 15 '14 at 13:27
  • @dasblinkenlight - I can't tell you right away, I'm haven't compiled some dependencies for debug mode or something and I'm getting some errors unrelated to this post. – user1594138 May 15 '14 at 13:28
  • This is not a template function; correct? – dlf May 15 '14 at 13:30
  • @dlf Template class but not a template function. – user1594138 May 15 '14 at 13:30
  • 4
    That's the answer then; template code is not instantiated unless something actually references it. And apparently when you instantiate a template class, it only instantiates the member functions you use (I can reproduce this). – dlf May 15 '14 at 13:32
  • @dlf Wow I forgot to think about that so I didn't mention it. I will delete this post then, or? Thanks for the answer. – user1594138 May 15 '14 at 13:35
  • 2
    @user1594138 Please update your question to reflect the reality. templated functions work very differently from normal function in this regard. You should also make it crystal clear which file you have your code in, so there is no doubt to whether your code is spread across many files, and whether the code is in header files that you actually use/include somewhere. – nos May 15 '14 at 13:36
  • @nos: seconded. Question is a vote to close in its current state. – Bathsheba May 15 '14 at 13:41
  • This is kind of a cool effect that I was not aware of before; it means you can write a template class with functions that contain code that only compiles with certain template parameter types, but as long as you don't call those functions, you can still instantiate it with other types too. – dlf May 15 '14 at 13:42
  • Before deleting, let me update my answer with the info from my comment above. I learned something from investigating this question, so maybe others could too. – dlf May 15 '14 at 13:47
  • @user1594138 Thank you for editing. Close vote retracted and +1 for what's now an intriguing question. – Bathsheba May 15 '14 at 14:08

1 Answers1

11

As revealed in comments, the reason this is happening is because remove() is a function in a class template. The compiler only instantiates template code if it is actually used; if you don't call remove(), it can have all the syntax errors you want and nobody will complain.

More formally, § 14.7.1 of the standard states (emphasis mine):

The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not the definitions or default arguments, of the class member functions

And later in the same section:

An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation.

(the word "implicit" is key here; if you use explicit template instantiation, the compiler will immediately try to instantiate all members using the indicated type(s) and fail if any doesn't compile)

This is not just an optimization; you can exploit this behavior to instantiate class templates with types that only support a subset of the template's operations. For example, suppose you write a template class that will be used with types that support a bar() operation, and in addition, some will also support baz(). You could do this:

template<typename T>
class Foo
{
private:
   T _myT;

public:
   void bar()
   {
      _myT.bar();
   }

   void baz()
   {
      _myT.baz();
   }
};

Now suppose you have these too:

struct BarAndBaz
{
   void bar() {}
   void baz() {}
};

struct BarOnly
{
   void bar() {}
};

This will compile and run just fine:

void f()
{
   Foo<BarAndBaz> foo1;
   foo1.bar();
   foo1.baz();

   Foo<BarOnly> foo2;
   foo2.bar();
   // don't try foo2.baz()!
   // or template class Foo<BarOnly>!
}
dlf
  • 9,045
  • 4
  • 32
  • 58
  • 2
    Might be worth mentioning explicit instantiation, which will immediately try to instantiate all member functions. Syntax is `template class Foo;`. – Mooing Duck May 15 '14 at 17:32
  • @MooingDuck That does seem like a worthwhile addition; edited – dlf May 15 '14 at 17:37