外部命名空间中带有非类型参数的友元函数模板不是友元

问题描述 投票:0回答:1

函数

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

c++ function templates namespaces friend
1个回答
0
投票

您需要做两件事才能做到这一点。

首先使用范围解析运算符

::
告诉编译器您想要与全局
make
交好。

第二个

::make
周围使用括号,否则编译器会将友元声明解析为试图与
make
的成员函数
std::array<int, N>
成为友元。

所以解决办法是:

template <std::size_t N> friend std::array<int, N> (::make)(int i);

工作演示

© www.soinside.com 2019 - 2024. All rights reserved.