如何将可变参数模板函数* instance *声明为朋友

时间:2018-11-30 22:24:23

标签: c++ c++14

我的问题扩展了这个问题:How to declare a variadic template function as a friend?

我知道如何使模板可变参数函数成为类的朋友 模板参数的 all 实例化。 但是我没有弄清楚如何仅从一些明确列出的实例中结识朋友。

示例:

template <typename T, typename... Args>
T create(Args&&... args)
{
    T t(forward<Args>(args)...);
    // ...
    return t;
}

class A {
public:
    /* -- This would allow to use all versions of constructors ..
    template <typename T, typename... Args>
    friend T create(Args&&... args);
    */
    // How to make these work?
    friend A create<A>(int);
    friend A create<A>(int, int);
    // .. is replacing T by A necessary at all?
protected:
    A() = default;  // < this should 'stay protected'!
    A(int) { }
    A(int, int) { }
};

目标是仅通过create的某些版本结交朋友, 这意味着我只需要某些版本的构造函数 可以公开访问,而其他人则不能访问。

我还希望朋友create仅遵循A返回类型(和构造函数),但是也许根本没有必要,因为朋友没有继承{{1} }可能不会受到A内部的影响?

该解决方案可能需要C ++ 14或更高版本的功能,但最好不需要较新的标准。

编辑

如果我只需要像A这样的基本类型,那么@ritesh解决方案将是完全令人满意的,因为复制元素与移动元素同样有效。 但是,我的用例实际上是不同的,需要避免不必要地复制更复杂的对象,并且构造函数可以具有通过值传递的参数,无论是作为副本还是将其传递到其中(我不记得该习惯用法是如何称为。参见下面的示例。

我已经完成了这个解决方案,它使用(并检查)@ Jarod42提出的正向引用。我使用了一个辅助结构int来演示如何复制和移动其对象。

E

幸运的是,仅将具有引用参数类型(template <typename T, typename... Args> T create(Args&&... args) /** ++ This would have copy E even if it is not necessary .. T create(Args... args) */ { T t(forward<Args>(args)...); // ... return t; } struct E { E() { cout << "E()" << endl; } E(const E&) { cout << "E(const E&)" << endl; } E& operator =(const E&) { cout << "= const E&" << endl; return *this; } E(E&&) { cout << "E(E&&)" << endl; } E& operator =(E&&) { cout << "= E&&" << endl; return *this; } }; class A { public: /** -- This would allow to use all versions of constructors .. template <typename T, typename... Args> friend T create(Args&&... args); */ friend A create<A>(const E&); friend A create<A>(E&); friend A create<A>(E&&); friend A create<A>(const E&, const E&); friend A create<A>(const E&, E&); friend A create<A>(const E&, E&&); friend A create<A>(E&, const E&); friend A create<A>(E&, E&); friend A create<A>(E&, E&&); friend A create<A>(E&&, const E&); friend A create<A>(E&&, E&); friend A create<A>(E&&, E&&); /** ++ This would have copy E even if it is not necessary .. friend A create<A>(E); friend A create<A>(E, E); */ protected: A() = default; //< this should 'stay protected'! A(E) { } //< either copy or move E A(const E&, E) { } //< must not copy the first argument }; const E&E&)但不包含E&&的变量声明为朋友就足够了:这就是{ {1}}会照顾好。

测试:

E

..将产生:

forward

我现在认为该解决方案有效,只是有点不舒服,因为有必要声明所有引用组合(包括E e; const E ce; cout << endl << "(E) <- (e) ..." << endl; create<A>(e); cout << endl << "(E) <- (ce) ..." << endl; create<A>(ce); cout << endl << "(E) <- (E()) ..." << endl; create<A>(E()); cout << endl << "(const E&, E) <- (e, e) ..." << endl; create<A>(e, e); cout << endl << "(const E&, E) <- (ce, ce) ..." << endl; create<A>(ce, ce); cout << endl << "(const E&, E) <- (ce, e) ..." << endl; create<A>(ce, e); cout << endl << "(const E&, E) <- (ce, E()) ..." << endl; create<A>(ce, E()); cout << endl << "(const E&, E) <- (move(e), E()) ..." << endl; create<A>(move(e), E()); ,否则传递E() E() (E) <- (e) ... E(const E&) (E) <- (ce) ... E(const E&) (E) <- (E()) ... E() E(E&&) (const E&, E) <- (e, e) ... E(const E&) (const E&, E) <- (ce, ce) ... E(const E&) (const E&, E) <- (ce, e) ... E(const E&) (const E&, E) <- (ce, E()) ... E() E(E&&) (const E&, E) <- (move(e), E()) ... E() E(E&&) 无效)。 如果有人知道如何缩短此时间(也许是通过使用模板而不是宏,我希望避免使用它们),请告诉我。

2 个答案:

答案 0 :(得分:4)

根据您的签名,它应该类似于:

friend A SOS::create<A>(int&&);
friend A SOS::create<A>(int&&, int&&);

friend A SOS::create<A>(int&);
friend A SOS::create<A>(int&, int&);

friend A SOS::create<A>(const int&);
friend A SOS::create<A>(const int&, const int&);

// ... mixing int&&, const int&    handles volatile

Demo

答案 1 :(得分:1)

此代码将起作用。

template <typename T, typename... Args>
T create(Args... args)
{
    return T(std::forward<Args>(args)...);

}

class A {
public:
    /*This will work*/
    friend A create<A>(int);
    friend A create<A>(int, int);
    void foo() { std::cout << "in foo" << std::endl; };
    // .. is replacing T by A necessary at all? 

protected:
    A() = default;  // < this should 'stay protected'!
    A(int) { };
    A(int, int) { };

};

回答您的问题

  

// ..完全用A代替T吗?

是的。因为不使用特殊类型替换它,所以将其称为部分特殊化。朋友声明不允许引用部分专业化。仅允许完全专业化。