【发布时间】:2018-12-02 07:28:17
【问题描述】:
我的问题扩展这个:How to declare a variadic template function as a friend?
我知道如何使模板可变参数函数成为类的朋友 所有模板参数的实例化。 但我不知道如何仅通过一些明确列出的实例来交朋友。
例子:
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的某些版本交朋友,
这意味着我只想要一些版本的构造函数
可以公开访问,但其他人不能访问。
我也希望朋友creates 只坚持A 返回类型(和构造函数),但也许根本没有必要,因为朋友没有继承,并且除A 之外的其他构造函数可能不会受到内部影响A?
该解决方案可能需要最高 C++14 的功能,但最好不要来自较新的标准。
编辑:
如果我只需要像int 这样的基本类型,那么@ritesh 解决方案将完全令人满意,因为复制元素与移动一样有效。
但是,我的用例实际上是不同的,需要避免不必要地复制更复杂的对象,并且构造函数可以具有按值传递的参数,无论是作为副本还是移入(我不记得这个成语是如何调用的..请参见下面的示例)。
我已经完成了这个解决方案,它使用(并检查)@Jarod42 提出的前向引用。我使用了一个辅助结构 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&&)的变体声明为友元就足够了,而不是 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&&)
我相信现在这个解决方案有效,只是有点不舒服,因为有必要声明所有引用组合(包括E&,否则传递e 将不起作用)。
如果有人知道如何缩短它(可能是通过使用模板,而不是宏,我尽量避免使用它们),请告诉我。
【问题讨论】: