views:

128

answers:

2

Hello,

I have following piece of code:

It compiles without problems under gcc-3.4, gcc-4.3, intel compiler, but fails under MSVC9.

MSVC tells "use of undefined type c_traits<C>, while compiling class template member function void foo<C>::go(void) with C=short.

The point it the compiler tries to install unused member function of unused class, because this class is just not used at all.

I can work-around the issue by specializing entire class foo instead of specializing its member function. But the point it that specializing entire class is little bit problematic for me for different reasons.

The big question: what is right?

  • Is my code wrong and gcc and intel compiler just ignore the issue because they do not install foo fully, or
  • The code is correct and this is bug of MSVC9 (VC 2008) that it tries to install unused member functions?

The code:

class base_foo {
public:
 virtual void go() {};
 virtual ~base_foo() {}
};
template<typename C>
struct c_traits;

template<>
struct c_traits<int> {
 typedef unsigned int_type;
};

template<typename C>
class foo : public base_foo {
public:
 static base_foo *create()
 {
  return new foo<C>();
 }
 virtual void go() 
 {
  typedef typename c_traits<C>::int_type int_type;
  int_type i;
  i=1;
 }
};

template<>
base_foo *foo<short>::create()
{
 return new base_foo();
}

int main()
{
 base_foo *a;
 a=foo<short>::create(); delete a;
 a=foo<int>::create(); delete a;
}
+1  A: 

The removal of unused functions will occur at linking not at compilation where you are having your error. MSVC may not know who amongst all the compilation units being compiled who will ultimately call that method. It can't know until compilation is complete and until linking occurs. Naturally different compilers may be smarter about this, but I suspect this may be what is happening.

I suspect your specific compiler errors sounds like it is caused by you having only forward declared

template<typename C>
struct c_traits;

you have not fully specified the class. Did you try something as simple as:

template<typename C>
struct c_traits 
{
    // some default/dummy int type
};

I suspect this would at least stop the compiler from complaining.

EDIT

this is generally wrong for class templates. Member functions of class templates aren't supposed to be compiled (and any errors in their bodies aren't supposed to be triggered) unless they're instantiated

The template is instantiated in this case in the form of:

 foo<short>

The compiler will treat this as any other class who's methods have potential for external linkage. I haven't heard any special language rule that says that external linkage doesn't apply to templates...?

Doug T.
He is complaining that compiler is even trying to compile the virtual method, since he's not calling the method, and not instantiating the class.
Pavel Minaev
I tried what you suggest: but it complains that `int_type` undefined.
Artyom
@Artyom: I think Doug meant that you should supply a dummy typedef where his comment was:template<typename C>struct c_traits{ typedef int int_type;};
Eclipse
This satisfies MSVC on my system, but you'll have to wait for someone like litb to elucidate on the standard.
Eclipse
the problem that even with dummy typedef would not compile because this type should have some properties that it does not have and thus should be specialized for something else.As I told the workaround is not a problem. I would just specialize full class, that's it. I just need to understand whether my code issue and what I'm doing is non-standard or this is MSVC compiler's issue.
Artyom
"The removal of unused functions will occur at linking not at compilation where you are having your error. " - this is generally wrong for class templates. Member functions of class templates aren't supposed to be compiled (and any errors in their bodies aren't supposed to be triggered) unless they're instantiated - i.e. called, or their address taken. Virtual functions are an exception to that.
Pavel Minaev
+3  A: 

Both compilers are right here; the behavior for your case is unspecified. ISO C++ 14.7.1[temp.inst]/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. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.

The reasoning for this is fairly simple: a virtual function requires a vtable entry, and with virtual dispatch, it may be tricky for the compiler to determine whether a given virtual function is actually called or not. Therefore, ISO C++ permits the compilers to do such advanced analysis for the sake of generating smaller code, but does not require it of them - so, as a C++ programmer, you should always assume that all virtual functions will always be instantiated.

Pavel Minaev
That'll teach me to stop at paragraph 3 of anything.
Michael Burr
Pavel Minaev
Ok thanks. So my code is wrong ;)
Artyom