将类模板声明为朋友而不知道其模板参数的最佳方法

时间:2019-02-11 12:07:09

标签: c++ templates friend

我偶然发现了一个场景,我试图找出最干净的方法,如果有的话。

我有一个带有受保护的构造函数的模板类,需要由一个朋友模板类实例化。两者共享部分模板参数,但不是全部。这是我的问题的一个例子。

我希望从经验丰富的程序员那里了解是否还有其他可能的解决方案(除了使构造函数公开之外,我认为没有其他解决方案),并且如果在两者之间我提出了一个比另一个更可接受的解决方案。 谢谢

解决方案1-我向具有受保护的构造函数(类Element)的类提供“不必要的”模板参数。

template <typename Tp_>
class Engine_Type_X
{
};
template <typename Tp_>
class Engine_Type_Z
{
};

//Forward declaration
template <typename Tp_, template<typename> typename Eng_>
class Container;

//Eng_ is only required to declare the friend class
template <typename Tp_,template<typename> typename Eng_> 
class Element
{
    friend class Container<Tp_,Eng_>;

    Tp_ tp_;
protected:  
    Element(Tp_ tp) : tp_{tp}   //protected ctor!!!
    {}
};

template <typename Tp_, template<typename> typename Eng_>
class Container
{
    using Element_tp = Element<Tp_,Eng_>;
    using Engine_tp  = Eng_<Tp_>;

    std::vector<Element_tp> container_;
    Engine_tp               &engine_;

public:
    Container(Engine_tp &engine) : container_{},engine_{engine}
    {}

    void install(Tp_ tp)
    {   Element_tp elem{tp};
        container_.emplace_back(elem);        
    }
};

解决方案2-我使用的方法类似于在这里How to declare a templated struct/class as a friend?

template <typename Tp_>
class Engine_Type_X
{
};
template <typename Tp_>
class Engine_Type_Z
{
};

template <typename Tp_>
class Element
{
    template<typename,template<typename>typename> friend class Container; //All templated classes are friend

    Tp_ tp_;
protected:  
    Element(Tp_ tp) : tp_{tp}   //protected ctor!!!
    {}
};

template <typename Tp_, template<typename> typename Eng_>
class Container
{
    using Element_tp = Element<Tp_>;
    using Engine_tp  = Eng_<Tp_>;

    std::vector<Element_tp> container_;
    Engine_tp               &engine_;

public:
    Container(Engine_tp &engine) : container_{},engine_{engine}
    {}

    void install(Tp_ tp)
    {   Element_tp elem{tp};
        container_.emplace_back(elem);        
    }
};

1 个答案:

答案 0 :(得分:0)

您仍然可以探索一些选择。

  1. 您可以将一个类设为内部类(称为嵌套类),该类将自动 将其作为“外部”类的朋友。参见https://en.cppreference.com/w/cpp/language/nested_types

  2. 另一种方法是要求使用所谓的“令牌”作为 构造函数,此令牌类型通常不使用模板参数,然后对其进行设置,以使该令牌只能是 由另一个类创建(可以是嵌套类型,也可以是嵌套类型)。

根据OP的要求,以下是完成2种方法的概述。选项:(使用c ++ 0x)

template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};

template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref>: std::true_type {};


template <class T>
class create_token {
    public:
    typedef T Type;
                 //copy of token not allowed !
    create_token(const create_token &) = delete; 
    create_token& operator=(const create_token &) = delete; 
                 //move is fine
    create_token(create_token &&) = default; 
    create_token& operator=(create_token &&) = default; 

    friend class T;
    private:
    create_token();
  };


template<class BlaBlaBla>
struct Element {
    template<class T>
    Element(create_token<T> t)  {
        static_assert(std::is_specialization<create_token<T>::Type, Container>::value, "Wrong type of token provided");
    }
};

template<class Whatever>
struct Container {
    template<class T>
    Element(create_token<T> t)  {
        static_assert(std::is_specialization<create_token<T>::Type, Element>::value, "Wrong type of token provided");
    }
};