考虑以下代码:
namespace foo {}
class A
{
class B
{
};
friend int foo::bar( B& );
};
namespace foo
{
int bar( A::B& )
{
}
}
Run Code Online (Sandbox Code Playgroud)
G ++ 4.4.3告诉我:
friendfun-innerclass.cpp:21:错误:'int foo :: bar(A :: B&)'应该在'foo'中声明
但我无法宣布:
namespace foo
{
int bar( A::B& );
}
Run Code Online (Sandbox Code Playgroud)
在A类定义之前因为A :: B尚未声明.而且我不能明确声明"A类:: B",声明类BI必须给出类A的定义,据我所知,"朋友"声明必须在A类的定义中.
对我来说很奇怪的是,如果我从命名空间foo中取出函数"bar()",一切正常.对我来说似乎违反直觉的是,在命名空间内部或不在命名空间内部使用函数会改变编译器是否接受类中的友元函数声明.
有没有人知道如何通过这种方式来构建所有声明并使其发挥作用?
为什么下面的代码用g ++编译好但是在clang上得到错误?
#include <iostream>
class Object {};
class Print
{
public:
template <typename CharT>
inline friend std::basic_ostream<CharT> & operator<<(std::basic_ostream<CharT> & out, const Object&)
{
return (out << "object");
}
static void f( const Object& str )
{
std::cout << str;
}
};
int main()
{
std::cout << Object() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我将友元函数移动到全局命名空间时,为两个编译器编译好的代码(clang ++/g ++).
在这种情况下,哪种实现更兼容C++ Standart?
我最近发现朋友声明范围遵循极其特殊的规则 - 如果你有一个friend函数或一个尚未声明的类的声明(定义),它会在直接封闭的命名空间中自动声明(定义),但它是不可见的不合格和合格的查询; 但是,友元函数声明通过依赖于参数的查找保持可见.
struct M {
friend void foo();
friend void bar(M);
};
void baz() {
foo(); // error, unqualified lookup cannot find it
::foo(); // error, qualified lookup cannot find it
bar(M()); // ok, thanks to ADL magic
}
Run Code Online (Sandbox Code Playgroud)
如果你看一下标准(参见链接的答案),他们就会付出很大的代价来启用这种古怪的行为,在复杂规则的限定/非限定查找中添加一个特定的例外.最终的结果让我感到非常困惑1,还有另一个案例要添加到实现中.作为
friend声明引用现有名称,期限; 要么似乎更容易实现,指定,最重要的是,理解,我想知道:为什么他们为这个烂摊子烦恼?他们试图覆盖哪些用例?在任何这些更简单的规则下(特别是第二个与现有行为最相似的规则)会破坏什么?
例如,在这种特殊情况下
struct M {
friend class N;
};
N *foo;
typedef int N;
Run Code Online (Sandbox Code Playgroud)
你得到可笑的精神分裂症错误信息
<source>:4:1: error: 'N' does not name …Run Code Online (Sandbox Code Playgroud)最小的例子:
class A
{
friend void swap(A& first, A& second) {}
void swap(A& other) {}
void call_swap(A& other)
{
swap(*this, other);
}
};
int main() { return 0; }
Run Code Online (Sandbox Code Playgroud)
g ++ 4.7说:
friend.cpp: In member function ‘void A::call_swap(A&)’:
friend.cpp:7:20: error: no matching function for call to ‘A::swap(A&, A&)’
friend.cpp:7:20: note: candidate is:
friend.cpp:4:7: note: void A::swap(A&)
friend.cpp:4:7: note: candidate expects 1 argument, 2 provided
Run Code Online (Sandbox Code Playgroud)
退出第4行:
// void swap(A& other) {}
Run Code Online (Sandbox Code Playgroud)
......它工作正常.如果我想保留交换功能的两种变体,为什么以及如何解决这个问题?
我与中描述的问题挣扎了这个问题(声明一个模板函数作为模板类的朋友),我相信第二个答案就是我想要做的(向前声明模板函数,然后将其命名一个专门为好友).我有一个问题,一个稍微不同的解决方案是否实际上是正确的,或者只是恰好在Visual C++ 2008中工作.
测试代码是:
#include <iostream>
// forward declarations
template <typename T>
class test;
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t);
template <typename T>
class test {
friend std::ostream& operator<< <T>(std::ostream &out, const test<T> &t);
// alternative friend declaration
// template <typename U>
// friend std::ostream& operator<<(std::ostream &out, const test<T> &t);
// rest of class
};
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t) {
// output function defined here
}
Run Code Online (Sandbox Code Playgroud)
首先,我发现一个奇怪的事情是,如果我更改前向声明operator<<以使其不匹配(例如std::ostream& …
众所周知,在 C++ 中,朋友的朋友不是(自动地)朋友。
然而,Clang 在 GCC 和 MSVC 的以下代码上有所不同:
class A {
public:
// forward declaration
class Inner2;
private:
class Inner1 {
char foo;
friend class Inner2;
};
public:
class Inner2 {
Inner1 i;
public:
bool operator==(Inner2 other) {
return i.foo == other.i.foo; // OK by GCC, Clang and MSVC++
}
friend bool operator!=(Inner2 a, Inner2 b) {
return a.i.foo != b.i.foo; // Clang accepts, GCC and MSVC++ reject
}
};
};
Run Code Online (Sandbox Code Playgroud)
代码:https …
可能吗?
class sample {
private:
int x;
public:
friend void fun();
};
Run Code Online (Sandbox Code Playgroud)
friend 函数没有参数!
在我看来不可能
因为朋友函数不是类的"成员"所以我们不能用类对象调用
喜欢:
sample s;
s.fun();
Run Code Online (Sandbox Code Playgroud) 如何将变量模板函数声明为朋友?
例如如下:
template<class T>
class A
{
friend ??? MakeA ??? ; // What should be placed here ???
A(T)
{}
};
template<class T, class... Args>
A<T> MakeA(Args&&... args)
{
T t(std::forward<Args>(args));
return A(t);
}
Run Code Online (Sandbox Code Playgroud) 我创建了一个类,我想强制任何试图构建对象的人使用unique_ptr.为此,我想到声明构造函数protected并使用friend返回a 的函数unique_ptr.所以这是我想要做的一个例子:
template <typename T>
class A
{
public:
friend std::unique_ptr<A<T>> CreateA<T>(int myarg);
protected:
A(int myarg) {}
};
template <typename T>
std::unique_ptr<A<T>> CreateA(int myarg)
{
// Since I declared CreateA as a friend I thought I
// would be able to do that
return std::make_unique<A<T>>(myarg);
}
Run Code Online (Sandbox Code Playgroud)
我做了一些有关朋友函数的阅读,我理解朋友函数可以访问类对象的私有/受保护成员.
无论如何我可以让我的榜样有效吗?
即使没有朋友功能,我的目标也是让某人创建对象CreateA的唯一方法.
编辑
我改变了一下代码.我没有提到我的类有一个模板参数.这显然使事情变得更加复杂.
考虑下面的类模板,它包含同一个朋友(相同的函数类型;见下文)的两个(隐藏)朋友声明,它也定义了朋友(因此朋友是内联的),但定义条件为(互斥)要求条款:
#include <iostream>
struct Base {};
template<int N>
struct S : public Base {
friend int foo(Base&) requires (N == 1) { return 1; }
friend int foo(Base&) requires (N == 2) { return 3; }
};
Run Code Online (Sandbox Code Playgroud)
[dcl.fct] / 8指出尾随需要子句是不函数的类型的一部分。重点矿]:
返回类型、参数类型列表、引用限定符、cv-qualifier-seq 和异常规范,但不是默认参数([dcl.fct.default])或尾部的 requires-clause ([ dcl.decl]),是函数类型的一部分。
这意味着对于两个定义都被实例化的情况,上述两个定义违反了 ODR;如果我们只关注单个翻译单元,[basic.def.odr]/1将被违反:
任何翻译单元不得包含任何变量、函数、类类型、枚举类型、模板、参数的默认参数(对于给定范围内的函数)或默认模板参数的多个定义。
并且在单个 TU 中,这种违规行为应该可以被诊断出来(不需要“格式错误,NDR”)。我正在尝试了解何时实例化上述定义的规则;或者如果这完全是实现定义的(或者甚至在到达实例化阶段之前格式错误)。
Clang 和 GCC (1) …
c++ ×10
friend-function ×10
friend ×3
templates ×3
c++11 ×1
c++20 ×1
clang++ ×1
class ×1
friend-class ×1
g++ ×1
name-lookup ×1
visual-c++ ×1