2

Consider the following header file:

// Foo.h
class Foo {
    public: template <typename T> void read(T& value);
};

It seems that assigning a pointer to Foo::read<T> in the constructor of a class, of which variable is then declared, cause instantiation:

// Foo.cc
#include "Foo.h"

template <typename T>
void Foo::read(T& value) { /* do something */ }

template <typename T> struct Bar {
    Bar<T>() { void (Foo::*funPtr)(T&) = &Foo::read<T>; }
};

static Bar<int  > bar1;
static Bar<long > bar2;
static Bar<float> bar3;

Is this solution reliable / portable / standard-conformant? (It works at least with Intel and GNU compilers.)

If you wonder why not to simply use template Foo::read<int>(int&); see this question.

Community
  • 1
  • 1
Daniel Langr
  • 22,196
  • 3
  • 50
  • 93
  • "Is this solution reliable / portable / standard-conformant?". I'm sorry. I can't find a problem statement in your question. How can there be a solution without a problem? – Johannes Schaub - litb Apr 20 '11 at 15:55
  • @Johannes: Sorry if it's not clear, please see the linked question for details. I simply don't know, if this "forced explicit instantiation" will work for all standard-compliant compilers. – Daniel Langr Apr 20 '11 at 16:30

3 Answers3

2

14.7.1 is where it's at. /2 says:

Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist.

Just like calling a function, taking a member function pointer requires that the function is defined in the program (perhaps in another TU). I believe that's what "requires a function definition to exist" means, so this is what causes the instantiation.

There's also /9:

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.

So the fact that GCC and Intel instantiate it suggests that everyone else should, since that which is not required is forbidden. Assuming everyone conforms, of course.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
2

Yes, your solution is portable. Here is a different way

template <typename T, T> struct user { };
template <typename T> struct Bar {
    typedef user< void (Foo::*)(T&), &Foo::read<T> > user_type;
};

Now whenever Bar<T> is implicitly instantiated, it will implicitly instanitate Foo::read<T>. No object needs to be created.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
1

When objects for Bar<type> are declared with actual types then definitely, Yes; it will instantiate Foo::read<type>(). However, it will be limited only to that function (say Foo::write<type>() will not be instantiated).

In other way, if you try something like this:

template<typename T>
struct X
{
  Bar<T> b1;  // this is required but not sufficient to instantiate Foo::read<T>()
};

Then Foo::read<int>() will not be instantiated until you declare X<int>.

Edit: In above example, directly declaring Bar<int> b1; (int instead of T) inside X is also NOT sufficient. Its containing type X<> has to be instantiated with actual (i.e. non-template) type.

iammilind
  • 68,093
  • 33
  • 169
  • 336