我的问题扩展了这个问题: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&&)
无效)。
如果有人知道如何缩短此时间(也许是通过使用模板而不是宏,我希望避免使用它们),请告诉我。
答案 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
答案 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吗?
是的。因为不使用特殊类型替换它,所以将其称为部分特殊化。朋友声明不允许引用部分专业化。仅允许完全专业化。