The function make()
has non type template parameter N
. That is decrared and defined in the global namespace.
The class target
is defined in the namespace ns
. That has a private constructor.
I want to create the target
instance, so I added friend declaration for the function template make()
.
However, compiler reports error calling a private constructor of class 'ns::target'
.
If I removed the namespace ns
, error is disappered. Why does it happen? Is there any good way to declare friend function template in this case?
Here is the code example that reproduces the issue. If you set USE_NS
to 0, ns
is removed and works fine.
#include <cstddef>
#include <array>
#include <iostream>
#define USE_NS 1 // if set to 0, works fine
// fwd
template <std::size_t N>
std::array<int, N> make(int i);
#if USE_NS
namespace ns {
#endif
struct target {
private:
template <std::size_t N>
friend
std::array<int, N> make(int i);
target(int i) {
std::cout << i << std::endl;
}
};
#if USE_NS
} // namespace ns
#endif
// def
template <std::size_t N>
std::array<int, N> make(int i) {
#if USE_NS
auto p = ns::target(i);
#else
auto p = target(i);
#endif
(void)p;
return std::array<int, N>{};
}
int main() {
make<2>(20);
make<4>(40);
}
godbolt link: https://godbolt.org/z/ado8nMfbW
I aslo tried declare the explicit specialization of make()
function template.
friend
std::array<int, 2> make<2>(int i);
friend
std::array<int, 4> make<4>(int i);
It works with namespace. But I can't use this approach because the value and numer of N
is unpredictable.
godbolt link: https://godbolt.org/z/Koas15hef
You need two things to do this.
First use the scope resolution operator ::
to tell the compiler that you want to befriend the global make
function template.
Second use parenthesis around ::make
like (::make)
to tell the compiler that make
is not a member function of std::array
. If you don't provide the parenthesis then the compiler will produce the error that there is no member function named make
in std::array
.
So the solution is:
template <std::size_t N> friend std::array<int, N> (::make)(int i);
The second reason is also explained in declaring a friend function in the global namespace that returns a template class