Error while Compiling in Visual Studio 2005

When I am compiling the following code on VC++6.0 I am not getting any errors.
But when i am doing the same thing I am getting errors
****************************************
template<class T>
class C {
      typedef void (T::*pFn) ();

        C(pFn pfnCleanup);

   typename T::X* x1;   // C4346
   // try the following line instead
     typename T::X* x;
};

template <class T>
C<T>::C(C::pFn pfnCleanup)
{
      ASSERT(pfnCleanup != NULL); // Error no clean up function provided
}
*****************************************


Errors:
==================================================================================
1>------ Build started: Project: 3rdParyLib, Configuration: Debug Win32 ------
1>Compiling...
1>3rdParyLib.cpp
1>c:\documents and settings\rn95079\my documents\visual studio 2005\projects\3rdparylib\3rdparylib\3rdparylib.cpp(81) : warning C4346: 'C<T>::pFn' : dependent name is not a type
1>        prefix with 'typename' to indicate a type
1>c:\documents and settings\rn95079\my documents\visual studio 2005\projects\3rdparylib\3rdparylib\3rdparylib.cpp(81) : error C2061: syntax error : identifier 'pFn'
1>c:\documents and settings\rn95079\my documents\visual studio 2005\projects\3rdparylib\3rdparylib\3rdparylib.cpp(84) : error C2244: 'C<T>::C' : unable to match function definition to an existing declaration
1>        c:\documents and settings\rn95079\my documents\visual studio 2005\projects\3rdparylib\3rdparylib\3rdparylib.cpp(73) : see declaration of 'C<T>::C'
1>        definition
1>        'C<T>::C(void)'
1>        existing declarations
1>        'C<T>::C(void (__thiscall T::* )(void))'
1>Build log was saved at "file://c:\Documents and Settings\rn95079\My Documents\Visual Studio 2005\Projects\3rdParyLib\3rdParyLib\Debug\BuildLog.htm"
1>3rdParyLib - 2 error(s), 1 warning(s)
============= Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ======================


Please let me know what kind of changes do I need to change..


nrkkalyanAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
evilrixConnect With a Mentor Senior Software Engineer (Avast)Commented:
See code below with your errors corrected. I've also provided you with some inline comments to give you feedback.

This web page explains a little more on the correct use of typename: http://www.codeguru.com/cpp/tic/tic0201.shtml

Basically, where a type is being used that is dependent on a template's dependent type you need to explicitly tell the compiler, otherwise it cannot know that it is. This is because T could be anything and therefore T::X (for example) could also be anything (function, type or data member). During the first pass of the template (templates are compile in two passes) the compiler knows nothing about T. the first pass is to sanity check the syntax of the template without reference to its dependent types (in this case T). This being the case you have to tell it that T::X is a type otherwise it'll assume it is not and will not understand T::X *x;

-Rx.
struct foo //<--- Just a test class, ignore
{
	typedef int X;
};
 
template<class T>
class C {
public:
	typedef void (C<T>::*pFn) ();
 
	C(pFn pfnCleanup); //<--- Having to pass in a pointer to member function doesn't make much sense!
 
	typename T::X* x1; //<--- You need typename since T is a dependent of this template (the compiler has no idea if X is a type, function or data member)
	typename T::X* x;
 
	void cleanup(){}; //<--- Since the constructor needs a pointer to member function, you'll need at least one otherwise you can't construct it
};
 
template <class T>
C<T>::C(typename C<T>::pFn pfnCleanup) //<--- Again, you need typename here as the compiler has no idea whether pFn is a type, function or data member
{
	ASSERT(pfnCleanup != NULL); // Error no clean up function provided
}
 
int main()
{
	C<foo> c(&C<foo>::cleanup); //<--- This is how you'll need to construct it (but I see little point i having to pass a pointer to member function)
	return 0;
}

Open in new window

0
 
Infinity08Commented:
The code you showed is not sufficient to explain the errors. Can you show more code ? (preferrably the whole file). Can you also point out which lines the errors refer to ?
0
 
Infinity08Commented:
>> But when i am doing the same thing I am getting errors

What does this mean btw ? Did you forget something ?
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
nrkkalyanAuthor Commented:
It means , when I am compiling the solution on visual studio 2005.

Any way I am attaching the code,

Rename the file to .zip.


dlls.bmp
0
 
Infinity08Commented:
The only thing I see wrong is that the definition of the C1 method is missing the return type int :

template <class T>
int C<T>::C1(C::pFn pfnCleanup)
{
      ASSERT(pfnCleanup != NULL); // Error no clean up function provided
      return 0;
}


I don't have Visual Studio 2005, nor VC++6.0, so I can't help you with that part. I can just say that the code looks ok to me.
0
 
IchijoCommented:
Try changing:

C<T>::C(C::pFn pfnCleanup)

to:

C<T>::C(pFn pfnCleanup)
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> When I am compiling the following code on VC++6.0 I am not getting any errors.
That's because VC6.0 breaks nearly all the rules about templates. VS2005 is correctly enforcing them. Do not use VC6.0 as your benchmark, your code will not be portable.
0
 
nrkkalyanAuthor Commented:
Good example...
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> VS2005 is correctly enforcing them
Actually, that's not 100% true either -- but it does do a better job :)

Consider the contrived code below. Strictly speaking it isn't valid C++ yet VS2005/8 will build it.

The error is on line 14, which should be written like this: c.template foo<T>();

odd syntax eh? The C++ standard defines the following special operators...

::template
.template
->template

They all exists for the same reason but pertain to static member functions, non-pointer accessed member functions and pointer accessed member functions.

So, the reason why this is not legal C++ is that foo is a member template function that relies on a dependent type. This being the case you must tell the compiler this nugget of information otherwise it will read the line as testing foo is less than T and that T is greater than (), which obviously makes little sense! The gcc compiler correctly flags this as an error...

14: error: expected primary-expression before '>' token
14: error: expected primary-expression before ')' token

The moral? MS compilers are not standards complaint when it comes to templates (in fact this applies to other areas as well but it is especially true for templates).

-Rx.
struct my_class
{
	template <typename T>
	void foo()
	{
	}
 
};
 
template <typename T>
void bar()
{
	T c;
	c.foo<T>();
}
 
int main()
{
	bar<my_class>();
 
	return 0;
}

Open in new window

0
 
Infinity08Commented:
???

        typedef void (C<T>::*pFn) ();

is not the same as :

        typedef void (T::*pFn) ();

I know it doesn't make a lot of sense, but it should still compile.

Anyway, because of that modification, you had to add typename here :

        template <class T>
        C<T>::C(typename C<T>::pFn pfnCleanup)

But the original code should have been fine, unless I'm missing something ...

I guess my question is : was that what you wanted to do, nrkkalyan ? Because the code evilrix posted is different from the code you posted.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> the original code should have been fine
Oops, my bad -- I got carried away (hungover atm). Corrected below. Thanks.

>> But the original code should have been fine, unless I'm missing something ...
template <class T>
C<T>::C(typename C<T>::pFn pfnCleanup) //<--- use typename as type pFn is reliant on a dependent type (not all compilers enforce this)
struct foo //<--- Just a test class, ignore
{
	typedef int X;
	void cleanup(){};
};
 
template<class T>
class C {
public:
	typedef void (T::*pFn) ();
 
	C(pFn pfnCleanup);
 
	typename T::X* x1;
	typename T::X* x;
};
 
template <class T>
C<T>::C(typename C<T>::pFn pfnCleanup)
{
	ASSERT(pfnCleanup != NULL); // Error no clean up function provided
}
 
int main()
{
	C<foo> c(&foo::cleanup);
	return 0;
}

Open in new window

0
 
Infinity08Commented:
>> (not all compilers enforce this)

I've been spoiled by my compiler apparently, as it doesn't need explicit typename's very often.
0
 
Infinity08Commented:
>> I've been spoiled by my compiler apparently, as it doesn't need explicit typename's very often.

Didn't need an explicit typename in this case either btw.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> I've been spoiled by my compiler apparently, as it doesn't need explicit typename's very often

Most compilers don't follow the standard strictly. The one that seems to be the closest, that I use, is gcc 3.2.
0
 
Infinity08Commented:
>> The one that seems to be the closest, that I use, is gcc 3.2.

Well, I've tried with gcc 3.4, and it didn't complain.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Didn't need an explicit typename in this case either btw.

http://www.codeguru.com/cpp/tic/tic0201.shtml

"The typename keyword tells the compiler to interpret a particular name as a type. It must be used for a name that:

1. Is a qualified name, one that is nested within another type.
2. Depends on a template argument. That is, a template argument is somehow involved in the name."
0
 
Infinity08Commented:
Yes, but that doesn't take into account the typedef ;) pFn was already defined as a type ...

From the standard :

        "A name used in a template declaration or definition and that is dependent on a template-parameter is
        assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified
        by the keyword typename."

and more specifically the part "unless the applicable name lookup finds a type name". Since pFn is a typedef, we find a type name, and there's no need for an explicit typename keyword.

IF the typename keyword is needed, you can simply place it in the typedef :

        typedef typename T::X TX;

and from then on use it without the typename keyword :

        TX tx;

Try the following code for example - it should compile and run just fine :

#include <iostream>
 
class Foo {
  public :
    typedef int X;
};
 
template <class T>
class Bar {
  public :
    typedef typename T::X TX;     // <--- typename keyword needed here !!
    void fun(TX tx);
};
 
template <class T>
void Bar<T>::fun(Bar::TX tx) {    // <--- no typename keyword needed
  std::cout << tx << std::endl;
}
 
int main(void) {
  Bar<Foo> bf;
  bf.fun(5);
  return 0;
}

Open in new window

0
 
Infinity08Commented:
Note also that we can complicate it as much as we want, for example :


#include <iostream>
 
template <class Y>
class Foo {
  public :
    typedef Y X;
};
 
template <class T>
class Bar {
  public :
    typedef typename T::X TX;     // <--- typename keyword needed here !!
    void fun(TX tx);
};
 
template <class T>
void Bar<T>::fun(Bar::TX tx) {    // <--- no typename keyword needed
  std::cout << tx << std::endl;
}
 
int main(void) {
  Bar<Foo<int> > bf;
  bf.fun(5);
  return 0;
}

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Is a qualified name, one that is nested within another type.
If you don't qualify pFn you can omit the use of typename

template <class T>
C<T>::C(pFn pfnCleanup)




0
 
evilrixSenior Software Engineer (Avast)Commented:
>> If you don't qualify pFn you can omit the use of typename

14.6.2.1 Dependent types

1. A type is dependent if it is
...
 a qualified-id with a nested-name-specifier which contains a class-name that names a dependent type or whose unqualified-id names a dependent type,
...
template <class T>
void Bar<T>::fun(typename Bar::TX tx) {    // <--- Qualified name
 
template <class T>
void Bar<T>::fun(TX tx) {    // <--- Unqualified name

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
As usual, the standard is ambiguous and implemented differently by different compilers. The truth of the matter is most compilers don't implement templates properly and, as such, don't just assume that because it builds on one compiler it'll build on another.

Anyway, I think we've done this to death now :)

-Rx.
0
 
Infinity08Commented:
My point is that TX is NOT a dependent type any more because of the typedef. I guess it comes down to interpretation of the standard again.

And in any case, it doesn't really matter, because nrkkalyan's problem with VS2005 is resolved.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> My point is that TX is NOT a dependent type any more because of the typedef.
According to 14.6.2.1 (in so far as I interpret it) it is if it is qualified. The qualification makes it a dependent type.

>> I guess it comes down to interpretation of the standard again.
Indeed. See my point above about interpretation of 14.6.2.1.

>> And in any case, it doesn't really matter, because nrkkalyan's problem with VS2005 is resolved.
Agreed. And once again you an I get to explore the mysteries of the Standards doc :)
0
 
Infinity08Commented:
Lol ... Give it a bit more time, and we can both recite it by heart ;)
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Lol ... Give it a bit more time, and we can both recite it by heart ;)
Lord I hope not ;)

Thanks I8. Once again, it was fun.
0
All Courses

From novice to tech pro — start learning today.