Force instantiation of friend functions - c++

Assume we have a template class with friend function:
template<class T>
class A {
friend A operator+ (int, const A&);
};
This function is implemented somewhere below:
template<class T>
A<T> operator+ (int i, const A<T>& a) {
...
}
And also there is force instantiation of class template further below:
template class A<int>;
Does this imply that operator+(int, A<int>) will be compiled? Or do I have to force instantiate it separately to achieve that?

Template parameters aren't automatically forwarded to friend declarations. You need to specify a template parameter for the function as well:
template<class T>
class A {
template<class U>
friend A<U> operator+ (int, const A<U>&);
};
Implementation is almost correct, should be
template<class T>
A<T> operator+ (int i, const A<T>& a) {
// ^^^
// ...
}

Related

operator== for classes inside a variadic template class

I have the following class structure:
template <typename...>
class SomeClass {
public:
class Foo { };
class Bar { };
};
I need to define operator== for SomeClass<Ts...>::Foo and SomeClass<Ts...>::Bar and I need to make it a friend of both Foo and Bar. The closest I got this to working is the following:
template <typename...>
class SomeClass {
public:
class Bar;
class Foo {
friend bool operator==(const Foo&, const Bar&) {
return true;
}
};
class Bar {
friend bool operator==(const Foo&, const Bar&);
};
};
Then I do:
SomeClass<int, double>::Foo foo;
SomeClass<int, double>::Bar bar;
foo == bar;
This compiles and works fine except for the fact that gcc gives me the warning:
warning: friend declaration `bool operator==(const SomeClass<Args>::Foo&, const SomeClass<Args>::Bar&)` declares a non-template function
note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
I kind of understand why this happens (operator== indeed depends on the template parameters of SomeClass), but how do I get rid of it? Adding <> to the second friend declaration, as suggested, only breaks compilation: the friending is no longer recognized and the compiler complaints about access to a private member.
I tried to modify the code according to the template friend declaration guide, but that only made things worse:
template <typename...>
class SomeClass;
template <typename... Args>
bool operator==(const typename SomeClass<Args...>::Foo&,
const typename SomeClass<Args...>::Bar&);
template <typename... Args>
class SomeClass {
public:
class Bar;
class Foo {
friend bool operator==<Args...>(const Foo&, const Bar&);
};
class Bar {
friend bool operator==<Args...>(const Foo&, const Bar&);
};
};
template <typename... Args>
bool operator==(const typename SomeClass<Args...>::Foo&,
const typename SomeClass<Args...>::Bar&) {
return true;
}
Now the weirdest thing happens when I call foo == bar:
error: no match for ‘operator==’ (operand types are ‘SomeClass<int, double>::Foo’ and ‘SomeClass<int, double>::Bar’)
note: candidate: ‘bool operator==(const typename SomeClass<Args ...>::Foo&, const typename SomeClass<Args ...>::Bar&) [with Args = {}; typename SomeClass<Args ...>::Foo = SomeClass<>::Foo; typename SomeClass<Args ...>::Bar = SomeClass<>::Bar]’ (reversed)
note: no known conversion for argument 1 from ‘SomeClass<int, double>::Bar’ to ‘const SomeClass<>::Foo&’
I.e. for some weird reason it tries to call the template specification with an empty arguments list and fails. Changing the operator type (to operator+) doesn't help (my idea was, this had something to do with C++20 new rules for comparison operators, but no).
So the questions I have are:
What's going on? I'm kind of confused, especially by the second part: why would the compiler try to call the operator for an empty parameter pack?
How do I avoid the warning in the first solution?
How do I define the operator outside of the class definition properly?
Ok, here are the results of some research I did.
In case of the friend in-class definition, according to cppreference, what it does is it generates non-template overloads of operator==. Thus, it is perfectly fine to reference them from the second friend declaration, and the code itself is correct. This is also why adding "<>" breaks the befriending: the overloads generated by the first definition are not template functions, while the second definition with the "<>" added now refers to some template overload that isn't definded.
Both Clang and MSVC compile that code without any problems, so the warning seems to be a GCC-only thing. I think, it is ok to suppress it.
The alternative would be to make the operator into a template, but unfortunately doing this properly for the parent class template parameters is impossible. This won't compile (see below why):
template <typename...>
class SomeClass {
public:
class Bar;
class Foo {
template <typename... Ts>
friend bool operator==(const typename SomeClass<Ts...>::Foo&,
const typename SomeClass<Ts...>::Bar&) {
return true;
}
};
class Bar {
template <typename... Ts>
friend bool operator==(const typename SomeClass<Ts...>::Foo&,
const typename SomeClass<Ts...>::Bar&);
};
};
The real alternative here is to trick GCC by making the operator template with some obsolete arguments, that could be deduced. And since default template arguments are forbidden in friend declarations, the only other hack I can think of is to make the operator variadic and use the fact that a trailing parameter pack that is not otherwise deduced, is deduced to an empty parameter pack. This works and emits no warnings in GCC:
template <typename...>
class SomeClass {
public:
class Bar;
class Foo {
template <typename...>
friend bool operator==(const Foo&, const Bar&) {
return true;
}
};
class Bar {
template <typename...>
friend bool operator==(const Foo&, const Bar&);
};
};
I really see no reason in doing that now, so the best thing to do is to pretend that you never saw this, and that I never wrote this.
Now, the second part, the outside definition. The problem here is that, as it turns out, there is no way in C++ to deduce template arguments (pack or not) of a parent class from a nested class.
I.e. a thing like this cannot possibly work:
template <typename T>
void foo(typename Parent<T>::Child) { }
foo(Parent<int>::Child{});
There even was a proposal to resolve this issue, but it was declined.
Defining operator== as a template function in my example above has exactly this problem: once the operator is called for SomeClass<int, double>::Foo and SomeClass<int, double>::Bar, the argument deduction is impossible (though the definition itself is correct), thus the compilation fails. This is also the answer to my first question: since the deduction is impossible, a parameter pack is deduced as an empty pack. Not at all what I intended.
The only workaround I came up with is to define the operator for the template non-nested arguments, and then restrict them. I am going to use C++20 concepts for this, although I think a SFINAE solution could be just as fine.
This works exactly as intended:
template <typename...>
class SomeClass;
template <typename T>
constexpr bool IsSomeClass = false;
template <typename... Args>
constexpr bool IsSomeClass<SomeClass<Args...>> = true;
template <typename T, typename U>
concept IsProperFooBar = requires {
typename T::Parent;
typename U::Parent;
requires std::same_as<typename T::Parent, typename U::Parent>;
requires IsSomeClass<typename T::Parent>;
requires std::same_as<std::decay_t<T>, typename T::Parent::Foo>;
requires std::same_as<std::decay_t<U>, typename U::Parent::Bar>;
};
template <typename T, typename U> requires IsProperFooBar<T, U>
bool operator==(const T&, const U&);
template <typename... Args>
class SomeClass {
public:
class Foo {
public:
using Parent = SomeClass;
private:
template <typename T, typename U> requires IsProperFooBar<T, U>
friend bool operator==(const T&, const U&);
};
class Bar {
public:
using Parent = SomeClass;
private:
template <typename T, typename U> requires IsProperFooBar<T, U>
friend bool operator==(const T&, const U&);
};
};
template <typename T, typename U> requires IsProperFooBar<T, U>
bool operator==(const T&, const U&) {
return true;
}
The only issue I see with this solution is that there is now a universal template operator==, so the concept will be checked every time you call == for anything, which may slow down compilation and emit unnecessary concept-not-satisfied diagnostic messages for other things.
On the plus side, there is no need in forward-declaring class Bar anymore, so at least I got that going for me, which is nice :-)
I got this solution with operator=='s definition outside the class.
There is no warning now, but I had to remove the friend qualifier. In order to access Foo's private methods from Bar's functions, declare Bar a friend of Foo (inside Foo). Do likewise for Bar if you want to access Bar's members from within Foo's methods.
Perhaps its a step forward. Hopes this helps.
#include <iostream>
template <typename... Args>
class SomeClass {
public:
class Bar;
class Foo;
class Foo {
public:
friend Bar;
bool operator==(const Bar&) const;
void do_something_to_Bar(Bar&);
private:
int _foo;
};
class Bar {
public:
friend Foo;
bool operator==(const Foo&) const;
void do_something_to_Foo(Foo&);
private:
int _bar;
};
};
template<typename... Args>
bool SomeClass<Args...>::Foo::operator== (const Bar& b) const {
return b._bar == _foo;
}
template<typename... Args>
bool SomeClass<Args...>::Bar::operator== (const Foo& f) const {
return f == *this;
}
template<typename... Args>
void SomeClass<Args...>::Bar::do_something_to_Foo(Foo& f) {
f._foo = 4;
_bar = 4;
}
template<typename... Args>
void SomeClass<Args...>::Foo::do_something_to_Bar(Bar& b) {
b._bar = 4;
_foo = 3;
}
int main() {
SomeClass<int,float>::Foo foo;
SomeClass<int,float>::Bar bar;
foo.do_something_to_Bar(bar);
std::cout << (foo == bar) << '\n';
std::cout << (bar == foo) << '\n';
bar.do_something_to_Foo(foo);
std::cout << (foo == bar) << '\n';
std::cout << (bar == foo) << '\n';
}
The definition of SomeClass<Args...>::Bar::operator== does not redefine the operator, but rather uses the definition of SomeClass<Args...>::Foo::operator==.

Template Friend Function / Class forward declaration

Why do we need template forward declaration for BlobPtr and operator overloading for template.
template <typename> class BlobPtr;
template <typename> class Blob;
template <typename T>
bool operator==(const Blob<T>&, const Blob<T>&);
template <typename T>
class Blob {
friend class BlobPtr<T>;
friend bool operator==<T>
(const Blob<T>&, const Blob<T>&);
};
class BlobPtr<T>{};
Blob<char> ca;
Blob<int> ia;
For for nontemplate class, forward declaration is not needed.
class Blob {
type
class BlobPtr;
friend bool operator==
(const Blob&, const Blob&);
};
class BlobPtr{};
If you want to declare the template in a friend declaration, you can just do that, you don't need forward declarations:
template <typename T>
class Blob {
template <typename U>
friend class BlobPtr;
template <typename U>
friend bool operator==(const Blob<U>&, const Blob<U>&);
};
This declares all instances of the templates as friends, not just the matching one. That is, BlobPtr<int> and BlobPtr<long> (and generally BlobPtr<Anything>) are all friends of Blob<int>.
If you want to declare a particular specialization of a template as a friend (so that BlobPtr<int> is a friend of Blob<int> but BlobPtr<long> is not), then you first need to tell the compiler that BlobPtr is a template in the first place - that's what you need forward declaration for.

Correct syntax for friend template function

In The C++ Programming Language, Fourth Edition - chapter 23.4.7 Friends, I found following example (I have slightly modified it to show only relevant part):
template<typename T>
class Vector {
public:
friend Vector operator*<>(const Vector& v, int f);
^^ ~~~~ ?
};
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f) {
return v;
}
I tried to compile it, but I get following error (clang):
main.cpp:8:20: error: friends can only be classes or functions
friend Vector operator*<>(const Vector& v, int f);
^
main.cpp:8:29: error: expected ';' at end of declaration list
friend Vector operator*<>(const Vector& v, int f);
^
;
2 errors generated.
Book explains that :
The <> after the name of the friend function is needed to make clear that the friend is a template function. Without the <>, a non template function would be assumed.
And that is all on this.
Without <> this code compiles, but when operator* is used (ex.: Vector<int> v; v*12;) then linker error appears:
main.cpp:(.text+0xb): undefined reference to `operator*(Vector<int> const&, int)'
So I assume that <> is needed to tell compiler that function template for operator* should be generated each time Vector template is instantiated for given type.
But what am I doing wrong in the example from the book, and why?
As the book said,
the <> after the name of the friend function is needed to make clear that the friend is a template function.
That means, the name should refer to a function template, which should be declared (as template) in advance. e.g.
// forward declaration of the class template
template<typename T>
class Vector;
// declaration of the function template
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f);
template<typename T>
class Vector {
public:
// friend declaration
friend Vector operator*<>(const Vector& v, int f);
};
// definition of the function template
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f) {
return v;
}
In your case, you're declaring operator* as a friend directly inside Vector, without any previous declaration. Therefore the correct syntax is:
template<typename T>
class Vector {
public:
template<typename>
friend Vector operator*(const Vector& v, int f);
};
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f) {
return v;
}
live example on wandbox
To make template friend method syntax work you need a forward declaration of this template method.
template<typename T>
class Vector;
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f);
template<typename T>
class Vector
{
template<typename T_> friend
Vector<T_> operator*(const Vector<T_>& v, int f);
};
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f)
{
return v;
}
Whatever book you're using is explaining it incorrectly.
What you need to do is
template<typename T>
class Vector
{
public:
friend Vector<T> operator*(const Vector<T>& v, int f);
};
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f)
{
return v;
}
The above makes the operator*() which accepts a Vector<T> a friend of Vector<T> but not a friend of Vector<U> (unless T is the same type as U).
Within the class definition it is possible to leave out the <T> from Vector<T>, but in my experience mere human beings seem to have more trouble convincing themselves that the function declaration and function definition correspond to each other. So I generally prefer not doing that .... your call though.
The <> syntax is used when explicitly specialising templates, but that's not what you are trying to do. For example, with a templated function;
template <class T> void foo(T) { /* whatever */ }
template<> void foo<int> {/* something specific to int */ }
Using <> is what C++ FAQ suggests, too.
But you can solve it by simply using the templated declaration like you would normally, except the parameters must be named differently from the class parameters. Then in the separate definition you can again use any type names:
template <typename T>
class Vector {
public:
T i{};
// Typename must be different from the class typename(s).
template <typename T_1>
friend ostream& operator<<(ostream& os, const Vector<T_1>& v);
};
// Typename can be any.
template <typename T>
ostream& operator<<(ostream& os, const Vector<T>& v) {
return os << v.i;
}
Live demo
That's all. No need for weird <> in-between function declaration, or pre-declarations.

Non-member operator overloading of inner class templates

I prefer to write definitions for class and function templates in a separate file which is automatically included after the "public" header. However, I've come to an interesting case where it looks like I can't do that.
template <typename T>
class Outer
{
public:
template <typename U>
class Inner
{
friend bool operator ==(const Inner& lhs, const Inner& rhs);
};
};
using Type = Outer<int>::Inner<short>;
int main()
{
Type a;
Type b;
a == b;
}
Is it possible to write definition of operator== separately that will work for any T and U?
For a particular specialization, yes:
template <typename T>
class Outer
{
public:
template <typename U>
class Inner
{
int x = 42;
friend bool operator ==(const Inner& lhs, const Inner& rhs);
};
};
using Type = Outer<int>::Inner<short>;
bool operator ==(const Type& lhs, const Type& rhs) {
return lhs.x == rhs.x;
}
int main()
{
Type a;
Type b;
a == b;
}
In your example, each specialization of the template befriends a non-template function that takes that particular specialization as parameters. You could define this function in-class (and then it will be stamped out every time the template is instantiated), or you could define it out-of-class - but then you would have to define one for every specialization you ever use.
As Igor Tandetnik points out, your example declares a non-template friend function, which you'll have to overload for each template instantiation, which is one reason friend functions are allowed to be defined inline (so they can be generated by the template without having to be templates themselves).
If you want to define the friend function as a template, here is the closest I was able to come up with:
template <typename T>
struct Outer {
template <typename U>
struct Inner;
};
template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & );
template <typename T>
template <typename U>
struct Outer<T>::Inner {
friend bool operator==<T,U>(Inner const &, Inner const &);
};
template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & ) {
return true;
}
// I switched this out, because my gcc-4.6 doesn't
// understand "using" aliases like this yet:
typedef Outer<int>::Inner<short> Type;
int main() {
Type a;
Type b;
operator==<int,short>( a, b );
}
Unfortunately, you'll notice the call site of this operator function is very awkward: operator==<int,short>( a, b ). I believe defining a function template on a nested class template like this disables (or at least interferes with) argument deduction, so you have to specify the template parameters explicitly (which means calling it as a function rather than in operator form). This is why the inline friend definition is so convenient. If you really want to define your operator=='s code separately, I'd recommend defining the friend inline to call another function template (with the proper template arguments), which you can then define out-of-line as a free function.

Overload output stream operator of a template class outside of the template

I want to overload the output stream operator << outside the template class definition.
Implementing it inside the template class is ok:
template
<typename T,int _MaxSize=10,template <class C> class Policy=NoCheck,typename Container=std::vector<T>>
class MyContainer : public Policy<T>
{
public:
MyContainer():p(_MaxSize){};
std::ostream& operator<<(MyContainer<T,_MaxSize,Policy,Container>& obj){ };
private:
Container p;
};
But when I tried to do it outside the template class:
template
<typename T,int _MaxSize=10,template <class C> class Policy=NoCheck,typename Container=std::vector<T>>
class MyContainer : public Policy<T>
{
public:
MyContainer():p(_MaxSize){};
friend std::ostream& operator<<(std::ostream& out,MyContainer<T,_MaxSize,Policy,Container> obj);
private:
Container p;
};
template
<typename T,int _MaxSize,template <class C> class Policy,typename Container>
std::ostream& operator<<(std::ostream& out,MyContainer<T,_MaxSize,Policy,Container> obj)
{
};
Compiler complains:
warning: friend declaration ‘std::ostream& operator<<(std::ostream&, MyContainer<T, _MaxSize, Policy, Container>)’ declares a non-template function [-Wnon-template-friend]
tempstruct.cc:39:97: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Can anybody give a simple example on how can the output stream operator << defined outside a template class?
In the related posts that I found here everyone do it inside the template class.
Can anybody give a simple example on how can the output stream operator << defined outside a template class?
No, because it's not simple. I can give a complicated example:
// Declare the class template, because we need it to declare the operator
template <typename,int,template <class C> class,typename> class MyContainer;
// Declare the operator, because (as the error says) templates must be declared
// in the namespace before you can declare them friends. At this point, we can't
// define the operator, since the class template is incomplete.
template
<typename T,int _MaxSize,template <class C> class Policy,typename Container>
std::ostream& operator<<(std::ostream&,MyContainer<T,_MaxSize,Policy,Container>);
// Define the class template
template
<typename T,int _MaxSize=10,template <class C> class Policy=NoCheck,typename Container=std::vector<T>>
class MyContainer : public Policy<T>
{
public:
MyContainer():p(_MaxSize){};
// Include <> to indicate that this is the template
friend std::ostream& operator<< <>(std::ostream& out,MyContainer<T,_MaxSize,Policy,Container> obj);
private:
Container p;
};
// Finally define the operator
template
<typename T,int _MaxSize,template <class C> class Policy,typename Container>
std::ostream& operator<<(std::ostream& out,MyContainer<T,_MaxSize,Policy,Container> obj)
{
// print some stuff
};
In the related posts that I found here everyone do it inside the template class.
I'd do that; it would be much simpler. Or, better still, I'd implement output in terms of the public interface, assuming it gives sufficient access to the container's contents. Then you wouldn't need the friend declaration, so wouldn't need the forward declarations either.