让我们在声明中定义f:作为朋友的函数:SS
struct S
{
friend void f() {}
};
Run Code Online (Sandbox Code Playgroud)
我找不到打电话的方法f.
struct S
{
friend void f() {}
friend void g(S const&) {}
} const s;
int main()
{
// f(); // error: 'f' was not declared in this scope
// S::f(); // error: 'f' is not a member of 'S'
g(s);
// S::g(s); // error: 'g' is not a member of 'S'
}
Run Code Online (Sandbox Code Playgroud)
额外奖励:如果我想获得函数指针/ std::function/ lambda g怎么办?
c++ friend language-lawyer name-lookup argument-dependent-lookup
在直观的层面上,有意义的是,需要不携带状态(通过引用或其他方式)的lambda应该可以干净地转换为裸函数指针.但是,我最近惊讶地看到GCC,Clang和MSVC中的以下失败:
int main(int, char *[]) {
void (*fp)() = []{}; // OK
//fp = [=]{}; // XXX - no user defined conversion operator available
//fp = [&]{}; // XXX - same ...
}
Run Code Online (Sandbox Code Playgroud)
C++ 17规范(或至少可见的公共草案版本N4713)在第8.4.5.1节[expr.prim.lambda.closure]的第7项中引用了带有和不带捕获的lambda:
没有lambda-capture的非泛型lambda表达式的闭包类型,其约束(如果有的话)被满足有一个转换函数指向函数,C++语言链接(10.5)具有与闭包类型相同的参数和返回类型函数调用运算符....
但是,查看正式语法,您可以在§8.4.5[expr.prim.lambda]中看到以下内容:
- lambda表达式:
- lambda-introducer复合语句
- ...
- lambda介绍人:
- [ lambda-capture opt ]
- ...
在§8.4.5.2 [expr.prim.lambda.capture]中:
- lambda-capture:
- 捕获的默认
- 捕捉列表
- capture-default,capture-list
- capture-default:
- &
- =
因此,所有编制者实际上都遵守了法律条文令我沮丧......
为什么语言将声明的存在定义为声明中的狭义语法区别,而不是基于主体是否包含对任何非静态/捕获状态的引用?
正如Scott Myers写的那样,你可以利用C++的类型系统中的松弛来声明clone()返回一个指向所声明的实际类型的指针:
class Base
{
virtual Base* clone() const = 0;
};
class Derived : public Base
{
virtual Derived* clone() const
};
Run Code Online (Sandbox Code Playgroud)
编译器检测到clone()返回指向对象类型的指针,并允许Derived覆盖它以返回指向派生的指针.
希望让clone()返回一个智能指针,它意味着所有权语义的转移,如下所示:
class Base
{
virtual std::auto_ptr<Base> clone() const = 0;
};
class Derived : public Base
{
virtual std::auto_ptr<Derived> clone() const;
};
Run Code Online (Sandbox Code Playgroud)
不幸的是,约定的放宽并不适用于模板化的智能指针,编译器也不允许覆盖.
所以,似乎我有两个选择:
这些方法之一是首选吗?或者有没有办法让我吃掉我的所有权语义转移并且我的强大类型安全呢?
它是在POSIX线程教程https://computing.llnl.gov/tutorials/pthreads/ 中编写的 ,这是一个逻辑错误.
我的问题是为什么它是一个逻辑错误?
在我的程序中,我需要使用这些信号,但是我不能保证会有一个处于_cond_wait状态的线程.我试图测试它,没有任何反应.这会导致意外行为还是更糟?
谢谢!
我有一些代码,为了这个问题的目的,归结为
template<typename T>
class TemplateClass : public T {
public:
void method() {}
template<typename U>
static void static_method(U u) { u.TemplateClass::method(); }
};
class EmptyClass {};
int main() {
TemplateClass<TemplateClass<EmptyClass> > c;
TemplateClass<EmptyClass>::static_method(c);
}
Run Code Online (Sandbox Code Playgroud)
我试图用两个版本的两个编译器来编译它.GCC 4.2,4.4,4.6接受它而没有投诉.截至11月14日的Clang 2.9和SVN中继拒绝它,并显示以下错误消息:
example.cc:6:38: error: lookup of 'TemplateClass' in member access expression is
ambiguous
static void static_method(U u) { u.TemplateClass::method(); }
^
example.cc:13:3: note: in instantiation of function template specialization
'TemplateClass<EmptyClass>::static_method<TemplateClass<TemplateClass<EmptyClass>
> >' requested here
TemplateClass<EmptyClass>::static_method(c);
^
example.cc:2:7: note: lookup in the object type
'TemplateClass<TemplateClass<EmptyClass> >' …Run Code Online (Sandbox Code Playgroud) 我有这个代码:
struct data {
void doNothing() {}
};
int main() {
data* ptr = new data();
ptr->~data();
ptr->doNothing();
::operator delete(ptr);
}
Run Code Online (Sandbox Code Playgroud)
请注意,doNothing()在对象被销毁之后但在其内存被释放之前被调用.看起来"对象生命周期"已经结束,但指针仍然指向正确分配的内存.成员函数不访问任何成员变量.
在这种情况下,成员函数调用是否合法?
c++ destructor object-lifetime language-lawyer explicit-destructor-call
以下程序
#include <algorithm>
#include <utility>
#include <memory>
namespace my_namespace
{
template<class T>
void swap(T& a, T& b)
{
T tmp = std::move(a);
a = std::move(b);
b = std::move(tmp);
}
template<class T, class Alloc = std::allocator<T>>
class foo {};
}
int main()
{
my_namespace::foo<int> *a, *b;
using my_namespace::swap;
swap(a,b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
导致两者g++并clang在我的系统上发出以下编译器错误:
$ clang -std=c++11 swap_repro.cpp -I.
swap_repro.cpp:28:3: error: call to 'swap' is ambiguous
swap(a,b);
^~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/bits/algorithmfwd.h:571:5: note: candidate function [with _Tp = my_namespace::foo<int, std::allocator<int> > …Run Code Online (Sandbox Code Playgroud) c++ namespaces class-template name-lookup argument-dependent-lookup
看看这段代码:
int a = 0xe+1;
Run Code Online (Sandbox Code Playgroud)
Clang,gcc,icc不编译这个:
t.cpp:1:12: error: invalid suffix '+' on integer constant
Run Code Online (Sandbox Code Playgroud)
MSVC成功编译.
哪个编译器正确?如果clang和gcc是正确的,为什么会发生这种情况?
注意:如果我之前添加空格+,代码将编译.如果我换0xe到0xf,它也会编译.也许这必须用指数表示法(比如1.2e+3)做一些事情?
示例代码:
struct S { int x; };
int func()
{
S s{2};
return (int &)s; // Equivalent to *reinterpret_cast<int *>(&s)
}
Run Code Online (Sandbox Code Playgroud)
我认为这很常见,被认为是可以接受的.该标准确保结构中没有初始填充.但是,这种情况未在严格别名规则(C++ 17 [basic.lval]/11)中列出:
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:
- (11.1)对象的动态类型,
- (11.2)对象的动态类型的cv限定版本,
- (11.3)与对象的动态类型类似(如7.5中所定义)的类型,
- (11.4)与对象的动态类型对应的有符号或无符号类型的类型,
- (11.5)一种类型,它是有符号或无符号类型,对应于对象动态类型的cv限定版本,
- (11.6)聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(递归地,包括子聚合或包含联合的元素或非静态数据成员),
- (11.7)一种类型,它是对象的动态类型的(可能是cv限定的)基类类型,
- (11.8)char,unsigned char或std :: byte类型.
很明显,对象s正在访问其存储值.
项目符号点中列出的类型是执行访问的glvalue的类型,而不是被访问对象的类型.在这段代码中,glvalue类型int不是聚合类型或联合类型,排除了11.6.
我的问题是:这个代码是否正确,如果是,那么允许上述哪一个要点?
我搜索了关于未对齐访问的标准,但没有找到任何东西(也许我是无意的).
是不确定的行为?它是实现定义的吗?
由于许多当前的CPU支持未对齐访问,因此未对齐的内存访问是实现定义的,这是明智的.是这样的吗?
通过未对齐访问,我的意思是例如:
alignas(int) char buffer[sizeof(int)+1];
int &x = *new(buffer+1) int;
x = 42;
Run Code Online (Sandbox Code Playgroud)