Is this code invalid:
template <class T> struct A;
class C {
template <class T> friend void A<T>::foo();
};
In GCC 6.1.0 it says:
error: member 'void A<T>::foo()' declared as friend before type 'A<T>' defined
template <class T> friend void A<T>::foo();
Clang 3.8.0:
warning: dependent nested name specifier 'A<T>::' for friend class declaration
is not supported; turning off access control for 'C' [-Wunsupported-friend]
And Visual Studio 2015 crashes:
fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'f:\dd\vctools\compiler\cxxfe\sl\p1\c\template.cpp', line 8952)
template <class T> friend void A<T>::foo();
More specifically, is A required to be defined before the friend declaration?
template <class T> struct A;
class C {
static void foo();
template <class T> friend void A<T>::f();
};
template <class T> struct A {
void f() { }
};
If so, why?
You refer to A's member function foo. This function is not known to exist yet, because you only forward declare A.
In other words, you'll have to declare A<T>::foo before C, as the GCC message tries to tell you (the other two are rather cryptic). This means you have to declare the complete interface of A before C, instead of only forward declaring it.
Solution
You can declare f as a friend of C in the following way:
class C;
template <class T> struct A {
void f(C const &c);
};
class C {
int i = 42;
public:
static void foo();
template <class T> friend void A<T>::f(C const &c);
};
template <class T> void A<T>::f(C const &c) { std::cout << c.i << std::endl; }
Live Demo
Justification
According to the standard §3.3.2/p6 Point of declaration [basic.scope.pdecl]:
After the point of declaration of a class member, the member name can
be looked up in the scope of its class. [ Note: this is true even if
the class is an incomplete class. For example,
struct X {
enum E { z = 16 };
int b[X::z]; // OK
};
— end note ]
The diagnostic is rather misleading both for GCC and CLANG. The real problem with your code is not the fact that you're trying to access the definition of an incomplete type, but rather is that you can only refer to a class member name only after it has been declared.
The first problem is (I think) from §9.3/7 [class.mfct] and probably some other places in the standard (see clang message below and 101010's answer):
Previously declared member functions may be mentioned in friend declarations.
This problem is similar to the one from this question.
Since you did not declare A<T>::f before C, you cannot declare it has a friend of C.
But there is an hidden problem behing clang's message, if you make A a non-templated class, the message is different:
Incomplete type A in nested name specifier.
Which is closer to gcc message than the actual one, this is because clang's warning is about something else. Per §14.5.4/5 [temp.friend], the standard allows member of class template to be friend, so this must be valid:
template <typename T>
struct A {
void f ();
};
class C {
template <typename T>
friend void A<T>::f(); // Ok, A<T>::f is already declared
void private_member (); // See below
};
But clang still complains:
warning: dependent nested name specifier 'A::' for friend class declaration
is not supported; turning off access control for 'C' [-Wunsupported-friend]
clang does not support such friend declaration, so it simply turns off access control for C, meaning that:
C c;
c.private_member();
Will be "valid" everywhere, which may not be what you want.
Firstly, Forward declaration of a class is not sufficient if you need to use the actual class type, for example, if you need to use it as a base class, or if you need to use the methods of the class in a method.
Since here you try to use its details "foo()", there is no way compiler knows what is A::foo().. Compiler cannot distinguish if it is a typo (or) actual function.. it needs to know the declaration of A::foo() before you can use it.
If you still want to only to forward declare the class and make it a friend, see if friend classes fit your situation
template <class T> struct A;
class C{
template <class T> friend struct A;
};
Related
So I have some code here that compiles with gcc, clang, and msvc:
#include <cstdio>
#include <type_traits>
struct c_class;
template <class T> struct holder { friend auto adl_lookup(holder<T>); };
template <class C, class T> struct lookup {
friend auto adl_lookup(holder<T>) { return holder<C>{}; }
};
struct cpp_class : lookup<cpp_class, c_class *> {
cpp_class() {}
};
int main() {
static_assert(std::is_same<holder<cpp_class>,
decltype(adl_lookup(holder<c_class *>{}))>{},
"Failed");
}
The reason adl_lookup is defined in the lookup class instead of the holder class is so that you can do a "reverse" lookup from c_class to cpp_class when you inherit from the CRTP class lookup<cpp_class, c_class *>. So the friend function can't be moved to the holder class.
However, on gcc I get a warning about non template friend function:
<source>:9:37: warning: friend declaration 'auto adl_lookup(holder<T>)' declares a non-template function [-Wnon-template-friend]
9 | friend auto adl_lookup(holder<T>);
| ^
<source>:9:37: note: (if this is not what you intended, make sure the function template has already been declared and add '<>' after the function name here)
If I try to fix this by forward declaring the function and then using <>, it doesnt compile with gcc or msvc(although it does compile with clang):
#include <cstdio>
#include <type_traits>
struct c_class;
template <class T> struct holder;
template <class T> auto adl_lookup(const holder<T> &);
template <class T> struct holder {};
template <class C, class T> struct lookup {
friend auto adl_lookup<>(const holder<T> &) { return holder<C>{}; }
};
struct cpp_class : lookup<cpp_class, c_class *> {
cpp_class() {}
};
int main() {
static_assert(std::is_same<holder<cpp_class>,
decltype(adl_lookup(holder<c_class *>{}))>{},
"Failed");
}
Am I using standard-compliant C++ here(in both snippets)? Is there a reason to be concerned about gcc's warning about non-template friend or is it just a false positive that I can safely ignore?
The second snippet is ill-formed, because a friend declaration cannot be a definition of a template specialization. An open clang bug report for accepting this is here.
The first one seems valid to me.
The warning by GCC is annoying, because defining a non-template function as friend is what you want to do here. Unfortunately I don't think there is any way to indicate in code that this is really what you want to do, but you can disable the warning with -Wno-non-template-friend. According to the documentation it is there for historical reasons, to identify pre-ISO-C++ compatibility issues where the syntax had a different meaning.
You should be aware that the ability to use friend injections of this kind to enable stateful metaprogramming may be considered unintended feature of the language and could maybe (I don't know) be restricted at some point in the future, see this question.
It is a common mistake, as using if (var = foo()) instead if (var == foo()) even if the code are legal.
Whereas adding extra parents allow to "inform" compiler of intent is the one expected in the =/== case.
if ((var = foo()))
There are no trick syntax to tell that it is really a non-template function that you want to use.
There are still traditional #pragma way to disable warning in specific region for given compiler (see how-to-disable-gcc-warnings-for-a-few-lines-of-code)
The title is a mouthful, but basically I wrote something like this:
enum EnumType{ValA, ValB};
template<EnumType> class A {};
template<>
class A<ValA>
{
private:
double param;
public:
A(double param);
};
template<>
A<ValA>::A(double param)
{
// Do Stuff
}
and when I try to compile it I get:
error: template-id 'A<>' for 'A<(EnumType)0u>::A(double)' does not
match any template declaration
Am I doing this wrong?
After searching online for similar cases, I tried to remove template<> (even though I don't understand why this would work), but then I get
multiple definition of 'A<(EnumType)0u>::A(double)'
I guess that I can replace template<> by inline (I tried and it compiles), but that doesn't feel like the proper way to do it (or if it is, I don't understand why).
Can someone explain to me what is wrong with what I wrote, why changing this seems to work, and what's the proper way to do it ?
Can someone explain to me what is wrong with what I wrote, why changing this seems to work, and what's the proper way to do it ?
The standard says:
Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax.
Therefore, in your case you must use:
A<EnumType::ValA>::A(double param)
{
// Do Stuff
}
No template<> at all is just fine. That's because you are actually specializing a (special) member function (the constructor) of an explicitly specialized class template.
See it on coliru.
It would have been different if no explicit specialization was given.
As a minimal working example:
enum EnumType{ValA, ValB};
template<EnumType> class A
{
private:
double param;
public:
A(double param);
};
template<>
A<EnumType::ValA>::A(double)
{
// Do Stuff
}
int main() {
A<EnumType::ValA> a{0.};
}
In this case, template<> is required before the definition of the constructor because you are not defining a specialization of a member function of an already specialized class template.
You missed a semicolon (;) at the the end of class definition.
And the non template member function can be defined this way:
A<ValA>::A(double param) {
// Do Stuff
}
Informally, the template parameter list is only written when necessary, for example, for defining a member function template of a class template, the two template parameter list should all be written
template<class U, class V>
class A{
template <class T>
A();
};
template<class U, class V>
template <class T>
A<U, V>::A() {}
and a empty template parameter list is needed for a explicit specialisation of function template (which, i guess, is the reason why you use so here), informally because it tells the compiler that this is not a function overloading.
Making an unknown friend
template<typename T>
class List
{
protected:
class a {
int x;
int y;
private:
friend class b; // <------------ Why this is not an error?
};
template <typename U > class b { //If that is not a error this should be an error
int z;
U y;
};
public:
List() {
a* ptr = (a *)new unsigned char[sizeof(a)];
}
};
int main() {
List<int> mylist;
}
Please go through this link, I have my questions as comments in the code.
I am trying to make another class a friend of my class. But that class is not know at the time of making friend. What is the C++ rule that allows for it.
Later I am defining that class in such a way that, it is incompatible with the friend declaration. Why is that not throwing an error.
Thanks
Yes your code is invalid! This is an interesting show of how templates can change meaning of code in subtle ways. The following code is valid:
class List
{
public:
class a {
typedef int type;
friend class b; // that's fine!
};
template <typename U > class b;
};
class b {
List::a::type an_int; // allowed to access private member
};
Standard says at 7.3.1.2/3
If a friend declaration in a non-local class first declares a class or function83) the friend class or function is a member of the innermost enclosing namespace.
When is it a "first declared class"? It says that too there
When looking for a prior declaration of a class or a function declared as a friend, and when the name of the friend class or function is neither a qualified name nor a template-id, scopes outside the innermost enclosing namespace scope are not considered.
The lookup for "class b" is delegated from 7.1.5.3/2 to 3.4.4 which in turn delegates to unqualified name lookup at 3.4/7. All the question now is whether the template-name "b" is visible in the friend declaration class a. If it isn't, the name is not found and the friend declaration will refer to a new declared class at global scope. 3.3.6/1 about the scope of it says
The potential scope of a name declared in a class consists not only of the declarative region following
the name’s declarator, but also of all function bodies, default arguments, and constructor ctor-
initializers in that class (including such things in nested classes).
Ignoring a few pedantic points that would make this wording not apply to here (which were a defect but are fixed in the C++0x version of that paragraph which also makes this easier to read), this list does not include the friend declaration as an area where that template name is visible.
However, the friend was declared in a member class of a class template. When the member class is instantiated different lookup applies - the lookup for friend names declared in a class template! The Standard says
Friend classes or functions can be declared within a class template. When a template is instantiated, the
names of its friends are treated as if the specialization had been explicitly declared at its point of instantiation.
So the following code is invalid:
template<typename T>
class List
{
public:
class a {
typedef int type;
friend class b; // that's fine!
};
template <typename U > class b;
};
// POI
List<int>::a x;
When that causes List<int>::a to be implicitly instantiated, the name a is looked up at "// POI" as if there would have been an explicit specialization declared. In that case, the template List::b has already been declared, and this lookup will hit it and emit an error because it's a template and not a non-template class.
//Run this- it now will compile for you
template <typename U > class b; //<----- forward declaration
template<typename T>
class List
{
protected:
class a {
int x;
int y;
private:
friend class b<T>; // <------------ Add <T>
};
template <typename U > class b {
int z;
U y;
};
public:
List() {
a* ptr = (a *)new unsigned char[sizeof(a)];
}
};
int main() {
List<int> mylist;
}
The code is ill-formed and Comeau rejects it giving the following error
error: invalid redeclaration of type name "b" (declared at
line 11)
I think this is a bug in g++. Intel C++ rejects it too. You can fix the code by defining class B above A.
template <typename U > class b {
int z;
U y;
};
class a {
int x;
int y;
private:
friend class b<T>;
};
just now I had to dig through the website to find out why template class template member function was giving syntax errors:
template<class C> class F00 {
template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here
I now realize that template brackets are treated as relational operators. To do what was intended the following bizarre syntax is needed, cf Templates: template function not playing well with class's template member function:
f.template bar<T>();
what other bizarre aspects and gotcha of C++/C++ templates you have encountered that were not something that you would consider to be common knowledge?
I got tripped up the first time I inherited a templated class from another templated class:
template<typename T>
class Base {
int a;
};
template<typename T>
class Derived : public Base<T> {
void func() {
a++; // error! 'a' has not been declared
}
};
The problem is that the compiler doesn't know if Base<T> is going to be the default template or a specialized one. A specialized version may not have int a as a member, so the compiler doesn't assume that it's available. But you can tell the compiler that it's going to be there with the using directive:
template<typename T>
class Derived : public Base<T> {
using Base<T>::a;
void func() {
a++; // OK!
}
};
Alternatively, you can make it explicit that you are using a member of T:
void func {
T::a++; // OK!
}
This one got me upset back then:
#include <vector>
using std::vector;
struct foo {
template<typename U>
void vector();
};
int main() {
foo f;
f.vector<int>(); // ambiguous!
}
The last line in main is ambiguous, because the compiler not only looks up vector within foo, but also as an unqualified name starting from within main. So it finds both std::vector and foo::vector. To fix this, you have to write
f.foo::vector<int>();
GCC does not care about that, and accepts the above code by doing the intuitive thing (calling the member), other compilers do better and warn like comeau:
"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
template "foo::vector" (declared at line 8) used in preference to
class template "std::vector" (declared at line 163 of
"stl_vector.h")
f.vector<int>(); // ambiguous!
The star of questions about templates here on SO: the missing typename!
template <typename T>
class vector
{
public:
typedef T * iterator;
...
};
template <typename T>
void func()
{
vector<T>::iterator it; // this is not correct!
typename vector<T>::iterator it2; // this is correct.
}
The problem here is that vector<T>::iterator is a dependent name: it depends on a template parameter. As a consequence, the compiler does not know that iterator designates a type; we need to tell him with the typename keyword.
The same goes for template inner classes or template member/static functions: they must be disambiguated using the template keyword, as noted in the OP.
template <typename T>
void func()
{
T::staticTemplateFunc<int>(); // ambiguous
T::template staticTemplateFunc<int>(); // ok
T t;
t.memberTemplateFunc<int>(); // ambiguous
t.template memberTemplateFunc<int>(); // ok
}
Out of scope class member function definition:
template <typename T>
class List { // a namespace scope class template
public:
template <typename T2> // a member function template
List (List<T2> const&); // (constructor)
…
};
template <typename T>
template <typename T2>
List<T>::List (List<T2> const& b) // an out-of-class member function
{ // template definition
…
}
Is there a difference between defining member functions for a template class inside the class declaration versus outside?
Defined inside:
template <typename T>
class A
{
public:
void method()
{
//...
}
};
Defined outside:
template <typename T>
class B
{
public:
void method();
};
template <typename T>
void B<T>::method()
{
//...
}
For non-template classes, this is the difference between inlined and non-inlined methods. Is this also true for template classes?
The default for most of my colleagues is to provide definitions inside the class, but I've always preferred definitions outside the class. Is my preference justified?
Edit: Please assume all the above code is provided in the header file for the class.
Yes, the exact same is true for template classes.
The reason why method definitions for template classes are usually preferred to be inline is that with templates, the entire definition must be visible when the template is instantiated.
So if you put the function definition in some separate .cpp file, you'll get a linker error.
The only general solution is to make the function inline, either by defining it inside the class or outside with the inline keyword. but in either cases, it must be visible anywhere the function is called, which means it must typically be in the same header as the class definition.
There's no difference, aside from having to type more. That includes the template bit, the inline and having to use more "elaborate" names when referring to the class. For example
template <typename T> class A {
A method(A a) {
// whatever
}
};
template <typename T> inline A<T> A<T>::method(A a) {
// whatever
}
Note that when the method is defined inside you can always omit the template parameter list <T> when referring to A<T> and just use A. When defining it outside, you have to use the "full" name in the return type and in the name of the method (but not in the parameter list).
I know this..I think it must be some what help full to u?
defining a member function outside of its template
It is not ok to provide the definition of a member function of a template class like this:
// This might be in a header file:
template <typename T>
class xyz {
void foo();
};
// ...
// This might be later on in the header file:
void xyz<T>::foo() {
// generic definition of foo()
}
This is wrong for a few reasons. So is this:
void xyz<class T>::foo() {
// generic definition of foo()
}
The proper definition needs the template keyword and the same template arguments that the class template's definition was declared with. So that gives:
template <typename T>
void xyz<T>::foo() {
// generic definition of foo()
}
Note that there are other types of template directives, such as member templates, etc., and each takes on their own form. What's important is to know which you have so you know how to write each flavor. This is so especially since the error messages of some compilers may not be clear as to what is wrong. And of course, get a good and up to date book.
If you have a nested member template within a template:
template <typename T>
struct xyz {
// ...
template <typename U>
struct abc;
// ...
};
How do you define abc outside of xyz? This does not work:
template <typename U>
struct xyz::abc<U> { // Nope
// ...
};
nor does this:
template <typename T, typename U>
struct xyz<T>::abc<U> { // Nope
// ...
};
You would have to do this:
template <typename T>
template <typename U>
struct xyz<T>::abc {
// ...
};
Note that it's ...abc not ...abc<U> because abc is a "primary" template. IOWs, this is not good:
// not allowed here:
template template struct xyz::abc { };