函数
make()
具有非类型模板参数 N
。这是在全局命名空间中声明和定义的。
类
target
定义在命名空间 ns
中。它有一个私有构造函数。
我想创建
target
实例,因此我为函数模板 make()
添加了友元声明。
但是,编译器报告错误
calling a private constructor of class 'ns::target'
。
如果我删除了命名空间
ns
,错误就会消失。为什么会发生这种情况?在这种情况下有什么好的方法来声明友元函数模板吗?
这是重现该问题的代码示例。如果将
USE_NS
设置为 0,ns
将被删除并正常工作。
#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 链接:https://godbolt.org/z/ado8nMfbW
我也尝试声明
make()
函数模板的显式专业化。
friend
std::array<int, 2> make<2>(int i);
friend
std::array<int, 4> make<4>(int i);
它与命名空间一起使用。但我不能使用这种方法,因为
N
的值和数量是不可预测的。
godbolt 链接:https://godbolt.org/z/Koas15hef
您需要做两件事才能做到这一点。
首先使用范围解析运算符
::
告诉编译器您想要与全局make
交好。
第二个在
::make
周围使用括号,否则编译器会将友元声明解析为试图与make
的成员函数std::array<int, N>
成为友元。
所以解决办法是:
template <std::size_t N> friend std::array<int, N> (::make)(int i);