Restrict the scope of class instances accessible by multiple template parameter friend function

╄→尐↘猪︶ㄣ 提交于 2019-12-10 13:15:55

问题


I would like to know if what I am aiming for is possible.

I have a class Class such that

#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;
}

But this way, f can access private/protected members of instances of Class where Class's type is not the same as f's arguments' type, like in the line

std::cout << R.m_t << std::endl;

(R is of type W, not T)

My question is this: is there a way I can define f as a friend function that has a template parameter specifying the return type (W), but can only access private/protected members of Class objects that are the same type as its arguments' type?

Edit 1: The solution submitted by @cantordust, while clean and aesthetic, doesn't work when Class and f are in a namespace, alas making it unsuitable for more general usecases. For example, if in a modification of cantordust's code namespace n starts just after the include declaration, and ends just before the main function, there will be no other way to use f than to put using n::f; in main, which, together with its implications, is inexcusable of well-written C++ code.

Edit 2: There is yet another solution: defining a member function, and optionally defining a similar regular function with the same parameters, and calling the member function from it. The code would look something like this:

// 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 */ }

The procedure for defining the regular function is obvious.


回答1:


You could indirect through a template class

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);
}

Live.

The indirection is necessary since you can't befriend a partial specialization.




回答2:


Under mild assumptions, you don't need a helper struct:

#include<iostream>

template<class T> class Class;
template<typename U, typename W>
Class<W> f(Class<U>& C, const Class<U>& 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<typename U, typename W>
    friend 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;
}

Demo here



来源:https://stackoverflow.com/questions/51556613/restrict-the-scope-of-class-instances-accessible-by-multiple-template-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!