0
votes

In the following code, A is a template class, depending on a non-type bool type parameter. A friend operator<< is defined for both A<true> and A<false>. The operator<< additionally depends on another bool template parameter.

#include <ostream>
#include <iostream>
#include <type_traits>

template <bool type>
class A;

template <>
class A<true> {
    int m_x;
public:
    A(int x) : m_x{x} { }
    template <bool d, bool type>
    friend std::ostream& operator<<(std::ostream& os, const A<type>& a);
};

template <>
class A<false> {
    int m_y;
public:
    A(int y) : m_y{y} { }
    template <bool d, bool type>
    friend std::ostream& operator<<(std::ostream& os, const A<type>& a);
};

template <bool d, bool type>
std::ostream& operator<<(std::ostream& os, const A<type>& a)
{
    if constexpr (type) {
        os << "m_x = " << a.m_x << std::endl;
        if constexpr (d) { os << "2m_x = " << a.m_x << std::endl; }
    }
    else {
        os << "m_y = " << a.m_y << std::endl;
        if constexpr (d) { os << "2m_y = " << a.m_y << std::endl; }
    }
    return os;
}


int main()
{
    A<true> atrue{2};
    A<false> afalse{3};

    operator<< <true>(std::cout, atrue);
    operator<< <false>(std::cout, atrue);

    operator<< <true>(std::cout, afalse);
    operator<< <false>(std::cout, afalse);

    return 0;
}

See it live on Coliru.

Now, I would like to give a default value of the template parameter d of operator<<, say d=false such that this statement

std::cout << atrue;

is equivalent to

operator<< <false>(std::cout, atrue);

because bool d takes a default value d=false and bool type is deduced from the second argument of operator<<.

Is there a syntax to allow for that?

If I insert the default parameter in the friend declaration

template <bool d = false, bool type>
friend std::ostream& operator<<(std::ostream& os, const A<type>& a);

I get a compile error:

main.cpp:14:71: error: default template arguments may not be used in template friend declarations

If I insert the default parameter in the code of operator<<

template <bool d = false, bool type>
std::ostream& operator<<(std::ostream& os, const A<type>& a)
{
...

again it does not compile giving error

main.cpp:27:15: error: redeclaration of friend 'template std::ostream& operator<<(std::ostream&, const A&)' may not have default template arguments

27 | std::ostream& operator<<(std::ostream& os, const A& a)

main.cpp:14:26: note: 'template std::ostream& operator<<(std::ostream&, const A&)' previously declared here

14 | friend std::ostream& operator<<(std::ostream& os, const A& a);

1
How about use other name than operator << as print as you cannot use it "normally"?Jarod42

1 Answers

1
votes

OK, actually the solution was relatively easy. It is enough to add a declaration of the template operator<< before the class specializations:

template <bool type>
class A;

template <bool d = false, bool type>
std::ostream& operator<<(std::ostream& os, const A<type>& a);
....

In this way the friend declaration inside A<type> does not declare operator<< in first place, but only declares that it is a friend. A working example can be checked here.