OK in Visual C++6.0 but not in Visual C++ .NET 2003?

G

Guest

I had a template library, the library was successfully compiled
on versrion 6.0 but when I tried to upgrade it in .NET version,
compilation had failed with the message like:

error C2248 'MyPLib::Basic2DArray<T>::m' : cannot access protected member
declared in 'PLib::Basic2DArray<T>'

The class implemented by

template <class T>
class Basic2DArray
{
public:
....
friend void InitializeArray(Basic2DArray<T>& a);
....
protected:
int m;
}

Why the code was not compiled in .NET version? In Visual C++ 6.0,
the library had no problem with compilation and link.
Please help me...
 
A

Antti Keskinen

Hello !

Visual C++ .NET has much stricter standard compliance than VS 6.0.

Your class declaration shows that you create a friend function
InitializeArray for Basic2DArray. This means that the InitializeArray
function can access the protected and private members of Basic2DArray.
However, the error code shows that you're trying to access the protected
member from somewhere where you ain't supposed to.

Double-clicking on the error would have shown you the line in which you're
trying to access it. If you would've copied this line as a part of the
message, I could've answered if you're doing something wrong.

Remember that declaring a friend function InitializeArray requires that the
definition of the function must be precisely alike. Could it be that you
forgot the template directive from the function declaration ? Or a similar
problem ?

Without more details, helping is quite difficult.

-Antti Keskinen
 
G

Guest

Could you do me a favor?
It is very lenthy to list details here, so it will be very
appreciated of you to try comile the following libray:
From the following link,
http://sourceforge.net/projects/libnurbs/
After downloading the "nurbs++=3.0.11" library and
Unzipping it, please try to build one of the projects
in the examples folder. You may have to modify the
project to load in the Visual C++ .NET environment...

Thank you very much in advance!
 
C

Carl Daniel [VC++ MVP]

hihaho said:
I had a template library, the library was successfully compiled
on versrion 6.0 but when I tried to upgrade it in .NET version,
compilation had failed with the message like:

error C2248 'MyPLib::Basic2DArray<T>::m' : cannot access protected
member declared in 'PLib::Basic2DArray<T>'

The class implemented by

template <class T>
class Basic2DArray
{
public:
...
friend void InitializeArray(Basic2DArray<T>& a);
...
protected:
int m;
}

Why the code was not compiled in .NET version? In Visual C++ 6.0,
the library had no problem with compilation and link.

The problem is that your code isn't standard compliant so it shouldn't
compile.

When you write

template <class T>
class X
{
friend void f(X<T>&);
};

you're declaring a namespace-scoped non-template function f(X<T>&) as a
friend.

When you subsequently write (you didn't show this, but I'm betting this is
what you did)

template <class T>
void f(X<T>&)
{
}

You're defining a template function. Under VC7 and before, the compiler
could not distinguish between instantiations of a template function like the
above and a non-template function with the same signature, so your code
"worked".

An example:

X<int> declares f(X<int>&) as a friend. VC6 could not tell the difference
between the <int> instantiation of a function template:

void f<int>(X<int>&);

and a non-template function

void f(X<int>&);

VC7.1 (.NET 2003) fixes this compiler bug, which breaks your code. So, what
are you to do? You have to declare your friend a little differently in
order to declare am instantiation of a function template as a friend:

// forward-declare the class template
template <class T> class X;

// forward-declare the function template
template <class T> void f(X<T>&);

// actual class definition
template <class T>
class X
{
friend void f<T>(X&);
};

// actual function definition
template <class T>
void f(X<T>&)
{
}

This makes f<T>(X<T>&) a friend of X<T>. It doesn't make any like-named
non-template functions friends, it also doesn't make f<U>(X<T>&) a friend of
X<T> (only instantiations with the same template argument list are friend).

HTH

-cd
 
A

Antti Keskinen

Hi !

The example you showed declared function template to be a friend of a class
template, correct ?

However, consider the following:

template<typename T>
class MyClass
{
friend void InitClass(MyClass<T>& refClass);
};

void InitClass(MyClass<T>& ref)
{
}

I believe this would result in an error with 'undefined variable T', yes ?
Would it be correct to move the function definition above the class
definition, mark it as a templated function, and forward-declare the class
template, like in

template<typename T>
class MyClass;

template<typename T>
void InitClass(MyClass<T>& refClass)
{
}

template<typename T>
class MyClass
{
friend void InitClass(MyClass<T>& refClass);
};

This would be the same thing you did, but with different semantics, no ? How
would you tackle the situation of "declaring/defining a non-templated
function, which takes an instantated MyClass of any type as a parameter" ?
Or is this impossible due to the fact that non-templated functions cannot
take "any type" parameters ? If it's a non-templated function, is the only
possibility to declare it for a defined set of types, as in:

template<typename T>
class MyClass
{
friend void InitClass(MyClass<T>& refClass);
};

void InitClass(MyClass<int>& refClass)
{
}

void InitClass(MyClass<double>& refClass)
{
}

void InitClass(MyClass<char>& refClass)
{
}

This would result in InitClass being a friend of MyClass<T> in cases where T
was of 'int', 'double' or 'long' type, but in other cases it would not be a
friend, correct ?

I know this sounds difficult and might feel irrelevant, but I'm just
intrigued by the template semantics, i.e. what does it actually mean to use
a template :)

-Antti Keskinen
 
C

Carl Daniel [VC++ MVP]

Antti said:
Hi !

The example you showed declared function template to be a friend of a
class template, correct ?

More precisely, it declared an instantion of a function template to be a
friend of an instantiation of a class template. Templates themselves have
no friends (so to speak).
However, consider the following:

template<typename T>
class MyClass
{
friend void InitClass(MyClass<T>& refClass);
};

void InitClass(MyClass<T>& ref)
{
}

I believe this would result in an error with 'undefined variable T',
yes ?
Correct.

Would it be correct to move the function definition above the
class definition, mark it as a templated function, and
forward-declare the class template, like in

template<typename T>
class MyClass;

template<typename T>
void InitClass(MyClass<T>& refClass)
{
}

template<typename T>
class MyClass
{
friend void InitClass(MyClass<T>& refClass);
};

Not quite.

friend void InitClass<T>(MyClass&);

If you don't use the InitClass<T> syntax, you're declaring a non-member
friend that's defined in the enclosing namespace. Even though there's a
template that matches the name and parameter list, it's not the friend
unless you use one of two syntaxes:

as above - an instantiation of the function template is a friend

template<class T> friend void InitClass(MyClass<T>&); - all instantiations
of the InitClass function template are friends of MyClass said:
This would be the same thing you did, but with different semantics,
no ? How would you tackle the situation of "declaring/defining a
non-templated function, which takes an instantated MyClass of any
type as a parameter" ?

Not possible, as you surmize. But the template friend declaration above
makes all instantions of a function template friends of the enclosing class
template.
Or is this impossible due to the fact that
non-templated functions cannot take "any type" parameters ? If it's a
non-templated function, is the only possibility to declare it for a
defined set of types, as in:
template<typename T>
class MyClass
{
friend void InitClass(MyClass<T>& refClass);
};

void InitClass(MyClass<int>& refClass)
{
}

void InitClass(MyClass<double>& refClass)
{
}

void InitClass(MyClass<char>& refClass)
{
}

This would result in InitClass being a friend of MyClass<T> in cases
where T was of 'int', 'double' or 'long' type, but in other cases it
would not be a friend, correct ?
Right.


I know this sounds difficult and might feel irrelevant, but I'm just
intrigued by the template semantics, i.e. what does it actually mean
to use a template :)

It's a good thing to understand - and an obscure corner of the language.
There are many possibilities when you mix templates and friends and it
definitely helps to know what each combination means.

-cd
 
A

Antti Keskinen

Hello !

A few more questions to help me clarify certain issues. In your previous
post, you used the syntax

friend void InitClass<T>(MyClass&);

to declare all InitClass<T> instantations as friends of MyClass<T> (so that
InitClass<U> is not a friend of MyClass<T>).

However, the curious thing about this comes from the parameter list. If I
had rewritten the friend declaration inside the class as

friend void InitClass<T>(MyClass<T>& refClass);

then how would this change the situation of who's a friend and who's not ?
Or is it just a "syntax error" situation ? Or is the <T> unrequired in the
parameter list because we are not talking about template declaration, but an
instantation of it, as in, the <T> gets "copied" into the place where the
template definition specifies it should go ?

Moreover, when writing the following:

template<typename T>
class MyClass;

template<typename T>
void InitClass(MyClass<T>& refClass)
{
}

template<typename T>
class MyClass
{
template<typename T> friend void InitClass(MyClass<T>& refClass);
};

Does the 'friend' keyword ensure that InitClass doesn't become some sort of
a nested-template declaration ? So this syntax means that all InitClass
instantations are friends of MyClass<T>, meaning, an InitClass<int> can
access MyClass<double>'s private/protected members ?

Also, if using a syntax like above, is it necessary to forward-declare the
MyClass<T> template before the function template ? Like, if I used the
"nested-template-looking" friend declaration of InitClass, I could move the
actual InitClass<T> definition to after or before the class definition, and
would not need any class declarations ?

Again, thank you for answering these questions. Like you stated, templates
are really one of the darkest corners of C++. But, very rewarding as well :D

-Antti Keskinen
 
V

Vladimir Nesterovsky

Are you arguing that such compiler awareness whether friend function is
template is correct?
Doesn't this violate the very nature of templates to be transparently built
into?
I do believe that a following code should compile just fine (which is the
case with Comeau C++ Online compiler):

template <class T>
class X
{
friend void f(X<T>&);

int y;
};

template <class T>
void f(X<T>& x)
{
x.y = 1;
}

int main()
{
X<int> x;

f(x);
}

Do you have any spec references why shouldn't this work?
--
Vladimir Nesterovsky
e-mail: (e-mail address removed)
home: www.nesterovsky-bros.com
The problem is that your code isn't standard compliant so it shouldn't
compile.

When you write

template <class T>
class X
{
friend void f(X<T>&);
};

you're declaring a namespace-scoped non-template function f(X<T>&) as a
friend.

When you subsequently write (you didn't show this, but I'm betting this is
what you did)

template <class T>
void f(X<T>&)
{
}

You're defining a template function. Under VC7 and before, the compiler
could not distinguish between instantiations of a template function like the
above and a non-template function with the same signature, so your code
"worked".

An example:

X<int> declares f(X<int>&) as a friend. VC6 could not tell the difference
between the <int> instantiation of a function template:

void f<int>(X<int>&);

and a non-template function

void f(X<int>&);

VC7.1 (.NET 2003) fixes this compiler bug, which breaks your code. So, what
are you to do? You have to declare your friend a little differently in
order to declare am instantiation of a function template as a friend:

// forward-declare the class template
template <class T> class X;

// forward-declare the function template
template <class T> void f(X<T>&);

// actual class definition
template <class T>
class X
{
friend void f<T>(X&);
};

// actual function definition
template <class T>
void f(X<T>&)
{
}

This makes f<T>(X<T>&) a friend of X<T>. It doesn't make any like-named
non-template functions friends, it also doesn't make f<U>(X<T>&) a friend of
X<T> (only instantiations with the same template argument list are
friend).
 
C

Carl Daniel [VC++ MVP]

Antti said:
Hello !

A few more questions to help me clarify certain issues. In your
previous post, you used the syntax

friend void InitClass<T>(MyClass&);

to declare all InitClass<T> instantations as friends of MyClass<T>
(so that InitClass<U> is not a friend of MyClass<T>).

The instantion of the InitClass function template with template argument <T>
is a friend of the instantiation of the MyClass template with template
arguments said:
However, the curious thing about this comes from the parameter list.
If I had rewritten the friend declaration inside the class as

friend void InitClass<T>(MyClass<T>& refClass);

They're equivalent. Within the definition of a class template, the name of
the template without a template argument list is synonymous with the fully
specified name. i.e. MyClass and MyClass said:
then how would this change the situation of who's a friend and who's
not ? Or is it just a "syntax error" situation ? Or is the <T>
unrequired in the parameter list because we are not talking about
template declaration, but an instantation of it, as in, the <T> gets
"copied" into the place where the template definition specifies it
should go ?
Exactly.


Moreover, when writing the following:

template<typename T>
class MyClass;

template<typename T>
void InitClass(MyClass<T>& refClass)
{
}

template<typename T>
class MyClass
{
template<typename T> friend void InitClass(MyClass<T>& refClass);
};

Does the 'friend' keyword ensure that InitClass doesn't become some
sort of a nested-template declaration ? So this syntax means that all
InitClass instantations are friends of MyClass<T>, meaning, an
InitClass<int> can access MyClass<double>'s private/protected members
?
Correct.


Also, if using a syntax like above, is it necessary to
forward-declare the MyClass<T> template before the function template
? Like, if I used the "nested-template-looking" friend declaration of
InitClass, I could move the actual InitClass<T> definition to after
or before the class definition, and would not need any class
declarations ?

It's necessary to forward-declare the class, otherwise it's impossible to
specifiy the parameter list for the function since MyClass is undefined at
that point.
Again, thank you for answering these questions. Like you stated,
templates are really one of the darkest corners of C++. But, very
rewarding as well :D

You're welcome!

-cd
 
C

Carl Daniel [VC++ MVP]

Vladimir said:
Are you arguing that such compiler awareness whether friend function
is template is correct?

Yes, it's correct.
Doesn't this violate the very nature of templates to be transparently
built into?

No, it's a quirk of friend declarations. When you write a friend
declaration, if no matching function is already visible, then a suitable
declaration is made in the enclosing scope, but that declaration is not a
template unless the friend declaration names a template (template <class T>
friend void f(X&)).. Templates don't have friends - instantiations of
template have friends.
I do believe that a following code should compile just fine (which is
the case with Comeau C++ Online compiler):

Remember, the Comeau online compiler doesn't link. The function template
f<T>(X<T>&) is never used in this program, so it's never instantiated. As a
result, the compiler doesn't complain about the access to x.y. Since the
online demo doesn't link, no error is generated for the namespace scoped
::f(X<int>&) that was implicitly declared by the friend declaration in the
instantiation of X said:
Do you have any spec references why shouldn't this work?

The C++ Standard. If you make me quote chapter and verse I'll have to do
some digging... but it's in there. Here are all the possibilitiies:

// Instantiation f<T> is a friend of instantiaion X<T>

template <class T>
class X;

template <class T>
void f(X<T>&);

template <class T>
class X
{
friend void f<T>(X<T>&);

int m;
};

template <class T>
void f(X<T>& x)
{
x.m = 1;

// Illegal - instantiations of f are only
// friends with a single instantiation of X
// with the same template arguments.
// reinterpret_cast<X<float>&>(x).m =1;
}

// All instantiations of g<U> are friends of Y<T>

template <class T>
class Y
{
template <class U>
friend void g(Y&);

int m;
};

template <class T>
void g(Y<T>& y)
{
y.m = 1;

// Legal - all instantions of g<U> are friends
// with all instantiations of Y<T>
reinterpret_cast<Y<float>&>(y).m =1;
}

// Non-template functions are friend of Z<T>

template <class T>
class Z
{
friend void h(Z<T>&);

int m;
};

void h(Z<int>& z)
{
z.m = 1;
// Illegal - this h is only a friend of
// Z<int>.
// reinterpret_cast<Z<float>&>(z).m =1;
}

void h(Z<float>& z)
{
z.m = 1;
// Illegal - this h is only a friend of
// Z<float>.
// reinterpret_cast<Z<int>&>(z).m =1;
}

int main()
{
X<int> x;
f(x);

Y<int> y;
g<int>(y);

Z<int> zi;
h(zi);
Z<float> zf;
h(zf);
}

-cd
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top