Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

nested template operator<< compilation error

24 views
Skip to first unread message

Pawel Por

unread,
Oct 18, 2022, 1:42:42 PM10/18/22
to
Hello,
I receive the following compilation errors:

error: non-template ‘BSTNode’ used as template
std::ostream& operator<<(std::ostream& out, const typename BST<T>::BSTNode<M>& elem)
note: use ‘BST<T>::template BSTNode’ to indicate that it is a template

error: too many template-parameter-lists
std::ostream& operator<<(std::ostream& out, const typename BST<T>::BSTNode<M>& elem)

Please help me to to solve this issue. Thank you in advance.
The code is as follows:

#include <iostream>

template<typename T>
class BST
{
template<typename L>
struct BSTNode
{
template<typename M>
friend std::ostream& operator<<(std::ostream& out, const BSTNode<M>& elem);
};
};

template<typename T>
template<typename M>
std::ostream& operator<<(std::ostream& out, const typename BST<T>::BSTNode<M>& elem) // !!! COMPILATION ERRORS !!!
{
out << elem.val;
return out;
}

int main(int argc, char **argv)
{
return 0;
}

Bonita Montero

unread,
Oct 18, 2022, 2:22:27 PM10/18/22
to
I think your class-template is nested and the calling operator mustn't
be nested.


Am 18.10.2022 um 19:42 schrieb Pawel Por:

> template<typename T>
> template<typename M>

template<typename T, typename M>

Andrey Tarasevich

unread,
Oct 18, 2022, 10:01:37 PM10/18/22
to
Your friend template it its current form has a non-template dependency
on the parameter `T` of the surrounding class template `BST`. Such
templates are legal in C++, but they can only be defined directly at the
point of declaration. C++ provides no syntax for defining them
out-of-class. If you define it right there, you should be fine

#include <iostream>

template<typename T>
struct BST
{
template<typename L>
struct BSTNode
{
int val = 42;

template<typename M>
friend std::ostream& operator<<(std::ostream& out,
const BSTNode<M>& elem)
{
out << elem.val;
return out;
}
};
};

int main(int argc, char **argv)
{
BST<int>::BSTNode<int> n;
std::cout << n;
}

However, this is still quite weird. Why did you decide to have
parameterized template dependency on the parameter `L` of `BSTNode`, but
no template dependency on the parameter `T` of `BST`? Either get rid of
both dependencies, i.e. turn your your operator into a non-template

#include <iostream>

template<typename T>
struct BST
{
template<typename L>
struct BSTNode
{
int val = 42;

friend std::ostream& operator<<(std::ostream& out,
const BSTNode& elem)
{
out << elem.val;
return out;
}
};
};

int main(int argc, char **argv)
{
BST<int>::BSTNode<int> n;
std::cout << n;
}

(note that in this variant you will still have to define the operator
in-class)

or keep both dependencies

#include <iostream>

template<typename T>
struct BST
{
template<typename L>
struct BSTNode
{
int val = 42;

template<typename U, typename V>
friend std::ostream&
operator<<(std::ostream& out,
const BST<U>::template BSTNode<V>& elem);
};
};

template<typename U, typename V>
std::ostream&
operator<<(std::ostream& out,
const typename BST<U>::template BSTNode<V>& elem)
{
out << elem.val;
return out;
}

int main(int argc, char **argv)
{
BST<int>::BSTNode<int> n;
operator<< <int>(std::cout, n);
}

In this variant it will become possible to define the friend function
outside the class. However, this version is problematic (read: useless)
since parameter `U` is in non-deduced context. The only way to call such
operator would be through a function calls syntax with explicit
specification of at least the first template argument, as shown in the
example above.

Basically, long story short, when it comes to templates prefer to define
friend functions right there in-class. That will save you from dealing
with some weird and unpleasant peculiarities of the language .

--
Best regards,
Andrey.

Andrey Tarasevich

unread,
Oct 18, 2022, 10:15:10 PM10/18/22
to
On 10/18/2022 11:22 AM, Bonita Montero wrote:
>
> template<typename T, typename M>
>
>> std::ostream& operator<<(std::ostream& out, const typename
>> BST<T>::BSTNode<M>& elem)        // !!! COMPILATION ERRORS !!!
>> {
>>    out << elem.val;
>>    return out;
>> }

Nope.

Firstly, this should be

template<typename T, typename M>
std::ostream&
operator<<(std::ostream& out,
const typename BST<T>::template BSTNode<M>& elem)
{
...

Secondly, even if it makes the code "compilable", it still won't define
the same function as declared by the friend declaration. This is a
definition of a completely different template. The friend remains
undefined. Any attempts to invoke the friend operator will result in
"undefined reference" error.

--
Best regards,
Andrey

Bonita Montero

unread,
Oct 19, 2022, 3:15:54 AM10/19/22
to
He needs to define a different friend with the same signature.

0 new messages