Function template instantiation and friend declaration - c++

I've just started learning templates in C++ and for practice purposes wrote this simple code
#include <iostream>
template<typename T>
class A;
template<typename T>
std::ostream& operator<<(std::ostream& out, A<T> x);
template <typename T>
class A
{
T m_x = 10;
public:
A(T x) : m_x{ x } {}
friend std::ostream& operator<< <T>(std::ostream& out, A x);
};
template<typename T>
std::ostream& operator<<(std::ostream& out, A<T> x)
{
out << "m_x = " << x.m_x;
return out;
}
int main()
{
A<int> a1{ 10 };
std::cout << a1 << '\n';
}
It works as expected, that is I get 10 as the output, but there is one thing that bothers me. At which point is the operator<< function instantiated? Does it happen at the point of creation of the a1 object (this is also the point where A<int> is implicitly instatiated, right?) or does it happen when I call the operator<< in std::cout << a1 << '\n'? My guess is that the second option is correct and I base it on this excerpt from cppreference which says that:
When code refers to a function in context that requires the function definition to exist, or if the existence of the definition affects the semantics of the program (since C++11), and this particular function has not been explicitly instantiated, implicit instantiation occurs.
But is it true that a friend declaration does not require the function definition to exist?
I'm sorry if this question is ill-pharased, I did my best to use the nomenclature right, but I'm just a beginner.
EDIT
What about this?
template <typename T>
class foo
{
T m_x;
friend void bar(foo x)
{
x.m_x = "123";
}
};
if I put a friend function definition inside a class, every instantiation of that class causes a new, ordinary function overload to be created that takes an argument of the current specialization, hence I would expect to see an error as soon as I write this: foo<int> x; but I don't get one... (for example, bar(x); causes the error)

I am not a language lawyer, so I'll try to answer with examples.
There are two aspects. First friend declaration.
A friend delcaration is a declaration. For example:
struct foo {
friend void bar();
};
int main() {
foo f;
}
Compiles and executes without any problem.
friend void bar(); declares a function bar. This functions is never defined. As long as we do not call it, thats not an issue. Of course, typically you would provide a definition, but if the function is never called you do not necessarily need to define it. Actually there are situations where having a declaration but no definition is on purpose, though thats out of scope of the quesiton.
Next, is templates and the question when member functions are instantiated. For that, consider this example:
#include <iostream>
template <typename T>
struct foo {
void bar() {
T x = "123";
}
};
int main() {
foo<int> x;
//x.bar();// error!
}
Compiles and executes without any problem.
Initializing an int with the string literal "123" is of course non-sense. Its only to provoke a compiler error when the method is instantiated. We can create an object of foo<int>. Though, we cannot call foo<int>::bar, because its not valid.
You can find many examples of methods of class templates that can only conditionally be instantiated in the standard library. For example std::map<key_t,value_t>::operator[]. It requires value_t to be default constructible, because it potentially has to default construct a value_t. You can use a std::map with a non-default-constructible value_t, you just cannot call its operator[]:
#include <map>
struct foo {
foo(int){}
};
int main() {
std::map<int,foo> x; // completely fine
x[1] = foo(1); // error
}
I spare you the complete error message. It is horrible, the essential part is:
error: no matching function for call to 'foo::foo()'

The overload of the operator<< in your case gives you an individual overload to every template classA<T>, so I can assume, that instantiation of operator<< can be with every instantiation of your class A<T>.
You can checkout this post, it can be useful in your case.

Related

Hidden friends: declarations and definitions

In his recent blog post Anthony Williams talks about hidden friends. The main idea, if I understood it correctly, is that functions declared as friends cannot be found by ADL in certain situations. Simple example:
namespace N {
struct A {
friend void foo(A) { }
};
struct B {
operator A();
};
// (*)
void bar(A) { }
}
void func() {
N::A a;
bar(a); // OK, bar is found via ADL
foo(a); // OK, foo is found via ADL
N::B b;
bar(b); // OK, bar is found via ADL
foo(b); // NOT OK, foo cannot be found
}
In all examples in the blog post, the friend functions are defined inside classes. Is it possible to declare a friend function and then define it later at the point (*), so that it remains hidden? It looks like hidden friends can only be defined in the class scope (or in another compilation unit).
Hidden friends need to be fully defined inline, i.e., inside of the definition of class. Yes, if you define friends somewhere else, where definition can cause namespace visibility, it would break restrictions based on hidden friends to be found as match by ADL search only, and as such be candidate for overload resolution.
Further more in WG21 recommendations for specifying hidden friends,
is noted that hidden friends are fully defined inline, like in this snippet:
#include <ostream>
#include <compare>
class C {
friend ostream& operator << ( ostream&, C const& ) {}
friend auto operator <=>( C const&, C const& ) = default;
};
Hidden friends can be defined out of line, but then they are not hidden in that TU. As an example, consider this header:
class A {
// this is hidden friend defined inline
friend int operator+(A, int) { return 0; }
// this is hidden friend defined out of line
friend int operator+(int, A);
// not a hidden friend (see below)
friend int operator+(A, A);
};
int operator+(A, A); // this is no longer hidden friend in any TU
and then a separate cpp file:
#include "a.hpp"
// This is not a hidden friend in this TU, but is in other TUs.
int A::operator+(int, A) {
return 2;
}
Doing this is useful when you have operators/ADL customization points that depend on other large headers for their implementation.

Inheritance with possible template failure

An error in a method that relies on template expansion only gives a compiler error when the method is explicitly called. Though when that method is marked as virtual, it produces a compiler error whether or not it is actually called. Is there anything in the C++ standard that explains why marking these methods as virtual causes a compiler error?
#include <memory>
#include <iostream>
template <class T_>
class Foo
{
protected:
T_ data;
public:
Foo(const T_& x) : data(x) { }
Foo(T_&& x) : data(std::move(x)) { }
// comment these two lines out and it works fine.
virtual void test(T_& x) = 0;
virtual void test(T_&& x) = 0;
};
template <class T_>
class Bar : public Foo<T_>
{
public:
using Foo<T_>::Foo;
void test(T_& x)
{
std::cout << "test(&)" << std::endl;
x = this->data;
}
void test(T_&& x)
{
std::cout << "test(&&)" << std::endl;
x = std::move(this->data);
}
};
int main()
{
Bar<std::unique_ptr<int>> x(std::unique_ptr<int>(new int(42)));
}
The overriders of virtual functions are always odr-used - that is, their definition must be present, whether they are explicitly used in a translation unit or not. Overriders of virtual functions are themselves virtual ([class.virtual]/2) and all virtual functions must be defined ([basic.def.odr]/3 and 4).
Now the question is whether the test overloads in the derived class are actually instantiated.
For templates, the standard mandates that
Unless a member of a class template […] has been
explicitly instantiated or explicitly specialized, the specialization
of the member is implicitly instantiated when the specialization is
referenced in a context that requires the member definition to exist;
For virtual functions one might argue that their presence is enough to require a definition. However, the standard doesn't tie itself down and leaves the decision to the implementation, [temp.inst]/11:
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.
Making it virtual is forcing instantiation. I get the same error with the following test code after commenting out the virtual function in the base class:
int main()
{
Bar<std::unique_ptr<int>> x(std::unique_ptr<int>(new int(42)));
x.test(std::unique_ptr<int>(new int(99)));
std::unique_ptr<int> pi;
x.test(pi);
std::cout << "test returned " << *pi << std::endl;
}
The version taking an reference can't be instantiated as std::unique_ptr is not assignable.

Friend function is not visible in the class

I have the following code:
struct M {
friend void f() {}
M() {
f(); // error: 'f' was not declared in this scope
}
};
int main() {
M m;
}
Live example
Both g++4.8 and clang3.4 fail to compile it, because f is not visible inside M, or so they say.
However, the Standard gives an example of a similar code
class M {
friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
and says that
A friend function defined in a class is in the (lexical) scope of the
class in which it is defined.
(ISO/IEC 14882:2011 11.3 Friends [class.friend] p6, p7)
From this I can't understand how compiler can't find f which is defined in same class where it's used.
It's kinda unlikely that both compilers have the same bug.
So, what did I miss?
The friend declaration states that a function called f in the surrounding namespace is a friend of the class; but it does not introduce the name f into the namespace. It's not available (except by argument-dependent lookup) until it's been declared in the namespace.
The relevant rule is C++11 7.3.1.2/3:
If a friend declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup or by qualified lookup until a matching declaration is provided in that namespace scope.
This quote from the C++ Standard
A friend function defined in a class is in the (lexical) scope of the
class in which it is defined.
means the following
9 Name lookup for a name used in the definition of a friend function
(11.3) defined inline in the class granting friendship shall proceed
as described for lookup in member function definitions.
That is any name used in the function is searched starting from the class scope.
However the function itself is not visible in the namespace until it will be declared outside the class.
So in your case it is enough to declare the function before the class definition
void f() {}
struct M {
friend void f();
M() {
f();
}
};
int main() {
M m;
}
Or
void f();
struct M {
friend void f() {}
M() {
f();
}
};
int main() {
M m;
}
The critical question is under what circumstances is the compiler able/allowed to find your function declaration.
For a general friend function, you have to declare it outside of the class such that the compiler is able to find it.
However there is a very useful exception: If the the friend function has an argument of class type, it is able to find the function without additional declaration due to argument-dependent name lookup.
This case is actually very important because normally you would want a friend function to access an object of class type.
Consider the following example:
#include <iostream>
struct M
{
friend void printI(int a) {
std::cout << a;
}
friend void print(const M& m) { // friend takes object of class type!
std::cout << "M";
}
void foo() {
printI(2); // ERROR - requires declaration!
print(*this); // OK!
}
};
int main()
{
M m;
m.foo();
printI(2); // ERROR - requires declaration!
print(m); // OK
}
struct M {
friend void f() {}
M() {
f(); // error: 'f' was not declared in this scope
}
};
int main() {
M m;
}
The above code works perfectly.(tried on DevC++)
Also try not to define the function inside the class as it might not have a scope outside it i.e. in main().
In trying to call f() from main() you'll receive an error saying function doesn't exist.
Therefore, define function outside classes using :: operator (if necessary) so that there is no problem accessing the function from anywhere.
Access friend function defined in class

What/where is the scope of friend functions definition defined in class template? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What’s the scope of inline friend functions?
Consider simple program :
template<typename T> struct foo{
friend void bar(){}
};
int main(){
foo<int>(); foo<float>();
}
Above code breaks the ODR rule, I wonder why? , also where is the scope of function bar ?
friend functions are not member functions; you just declare friendship inside a class, but the function is always a free function. If you define it inside a class template class, you will end up defining it as many times as template instances you have.
I will try to explain that with code. For our purposes, your code is equivalent to this:
template<typename T> struct foo{
};
template<> struct foo<int>{
friend void bar();
};
void bar() {};
template<> struct foo<double>{
friend void bar();
};
void bar() {};
int main(){
foo<int>(); foo<float>();
}
Because your code defines the free function void bar() twice, or lets rather say, your templates produces for each instantiation a new function named void bar(), which happens to have the exact same signature each time, therefore you have multiple functions with the same signature, which is a breach of ODR.
The technique at hand is called "Friend Name Injection", because you inject a name into the surrounding namespace.
You have defined the bar inside your struct. This leads to double definition of bar func, once per template instantiation. Friend should be only a declaration of some entity. The entity itself (func in your case) should be defined elsewhere. Replace your bar definition with friend void bar(); declaration and define your bar in another place.

Declaring an instance of an explicit specializtion of a template within a regular class

I can't get this to compile at all. I may not be possible but I don't know why it should not be.
class A {
template <typename T>
class B {
int test() { return 0; }
};
//template <> class B<int>; <-with this, namepace error
B<int> myB_;
};
template <> class A::B<int> {
int test() {
return 1;
}
};
As it appears the compiler complains "The explicit specialization "class A::B" must be declared before it is used."
If I try to provide the froward declaration in the commented line, the compiler complains
"The explicit specialization "B" must be declared in the namespace containing the template."
We use 2 different compilers here. This error is from IBM's "xl" compiler on AIX but I get similar errors with different verbage when compiling on our Sun systems.
It seems like a catch-22.
Obviously, this is a highly contrived, simplistic example but, it represents the problem.
I want to define a template class within a class because the template class is only relevent to the containing class. There should be no access to the template from outside the class.
Am I missing something?
You are correct. This is not possible to do (as far as I know). Your member declaration causes an implicit instantiation before the explicit specialization was declared. But how would you want to declare it? You cannot do that in class scope. Others have felt that this is an ugly restriction.
You could work around this by making the class member a pointer. This would not need to implicitly instantiate the class at that point, but rather at the point where you create the object in the end. I realize that this is an ugly work around. So better find other ways to do this.
For instance partial specializations are allowed in class scope. So you could add a dummy template parameter, then you can specialize this in the class before the member declaration. Likewise, i find this ugly, but it would not disturb things that much, I feel.
You could work around the issue by using an unnamed namespace for privacy:
namespace {
template <typename T>
class B {
int test() { return 0; }
};
template <> class B<int> {
int test() {
return 1;
}
};
}
class A {
B<int> myB_;
};
This will compile, but if A needs to be visible outside this compilation unit, you'll need more elaborate machinery (e.g., interface and factory or Pimpl).
B is not a template class and you are trying to specialize it. That is the cause for the error. You can check these two errors C2913 and C3413.
Is this what you are looking for?
class A
{
template<class T>
class B
{
inline int test()
{
return 0;
}
};
A::B<int> myB_;
};