限制多个模板参数友元函数可访问的类实例的范围

use*_*474 6 c++ templates friend friend-function c++14

我想知道我的目标是否可行.

我有一个类Class

#include<iostream>

template<class T> class Class;
template<class T, class W> Class<W> f(Class<T>& C, const Class<T>& D);

template<class T> class Class {
protected: // this could be private
    T m_t;
public:
    Class(): m_t(T()) {}
    Class(T t): m_t(t) {}
    T& getT() { return m_t; }
    template<class U, class W> friend Class<W> f(Class<U>& C, const Class<U>& D);
};

template<class T, class W> Class<W> f(Class<T>& C, const Class<T>& D)
{
    C.m_t += D.m_t;
    Class<W> R;
    std::cout << R.m_t << std::endl; // I don't want this to be possible
    return R;
}

int main()
{
    Class<int> C(42), D(24);
    std::cout << f<int, char>(C, D).getT() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

但是这样,f可以访问Class实例的私有/受保护成员,其中Class的类型与f的参数类型不同,就像在行中一样

std::cout << R.m_t << std::endl;
Run Code Online (Sandbox Code Playgroud)

(R是W型,而不是T型)

我的问题是:有没有办法可以将f定义为友元函数,该函数具有指定返回类型(W)的模板参数,但只能访问与其参数类型相同的Class对象的私有/受保护成员'类型?

编辑1:@cantordust提交的解决方案,虽然干净和美观,但是当Class和f在命名空间中时不起作用,唉它不适合更常用的用例.例如,如果cantordust代码的修改namespace n在include声明之后开始,并且在main函数之前结束,则没有其他方法可以使用而f不是放入using n::f;main,这与其含义一起,是不可原谅的.写的C++代码.

编辑2:还有另一种解决方案:定义成员函数,并可选择使用相同的参数定义类似的常规函数​​,并从中调用成员函数.代码看起来像这样:

// inside Class
template<class W> Class<W> f(Class& C, Class& D);
//outside Class
template<class T> template<class W> Class<W> Class<T>::f(Class<T>& C, Class<T>& D)
{ /* definition */ }
Run Code Online (Sandbox Code Playgroud)

定义常规函数的过程是显而易见的.

Pas*_* By 3

您可以通过模板类间接

template<class T> class Class;
template<typename>
struct fs;

template<class T> class Class {
protected: // this could be private
    T m_t;
public:
    Class(): m_t(T()) {}
    Class(T t): m_t(t) {}
    T& getT() { return m_t; }
    friend struct fs<T>;
};

template<typename T>
struct fs
{
    template<typename W>
    static Class<W> f(Class<T>& C, const Class<T>& D)
    {
        C.m_t += D.m_t;
        Class<W> R;
        std::cout << R.m_t << std::endl; // ill-formed
        return R;
    }
};

template<class T, class W>
Class<W> f(Class<T>& C, const Class<T>& D)
{
    return fs<T>::template f<W>(C, D);
}
Run Code Online (Sandbox Code Playgroud)

居住

间接是必要的,因为你无法与部分专业化成为朋友。