Fer*_*cio 308
大多数C++程序员都熟悉三元运算符:
x = (y < 0) ? 10 : 20;
Run Code Online (Sandbox Code Playgroud)
但是,他们没有意识到它可以用作左值:
(a == 0 ? a : b) = 1;
Run Code Online (Sandbox Code Playgroud)
这是简写
if (a == 0)
a = 1;
else
b = 1;
Run Code Online (Sandbox Code Playgroud)
谨慎使用:-)
小智 239
您可以将URI放入C++源代码而不会出错.例如:
void foo() {
http://stackoverflow.com/
int bar = 4;
...
}
Run Code Online (Sandbox Code Playgroud)
pae*_*bal 119
我同意那里的大多数帖子:C++是一种多范式语言,所以你会发现的"隐藏"功能(除了"不定义的行为",你应该不惜一切代价避免)是聪明的设施使用.
大多数这些设施不是语言的内置功能,而是基于库的功能.
最重要的是RAII,多年来C++开发人员经常忽略来自C世界.运算符重载通常是一个误解的特性,它支持类似数组的行为(下标运算符),类似指针的操作(智能指针)和类似内置的操作(乘法矩阵).
使用异常通常很困难,但通过一些工作,可以通过异常安全规范生成非常强大的代码(包括不会失败的代码,或者具有类似提交功能的代码,或者恢复为它的原始状态).
C++中最着名的"隐藏"功能是模板元编程,因为它使您可以在编译时而不是运行时部分(或完全)执行程序.但这很困难,在尝试之前,您必须牢牢掌握模板.
其他人利用多范式在C++的祖先之外产生"编程方式",即C.
通过使用仿函数,你可以模拟功能,具有额外的类型安全并且是有状态的.使用命令模式,可以延迟代码执行.大多数其他设计模式可以在C++中轻松有效地实现,以产生不应该在"官方C++范例"列表中的替代编码样式.
通过使用模板,您可以生成适用于大多数类型的代码,包括不是您最初想到的代码.您也可以增加类型安全性(如自动类型安全malloc/realloc/free).C++对象的功能非常强大(因此,如果不小心使用会很危险),但即使是动态多态也有其在C++中的静态版本:CRTP.
我发现,来自Scott Meyers的大多数" Effective C++ "类书籍或来自Herb Sutter的" Exceptional C++ "类书籍都易于阅读,并且对C++的已知和鲜为人知的特性有很多信息.
在我的首选中,应该让任何Java程序员的头发从恐怖中崛起:在C++中,向对象添加功能的最面向对象的方式是通过非成员非朋友功能,而不是成员 -函数(即类方法),因为:
在C++中,类的接口既是其成员函数,也是同一名称空间中的非成员函数
非朋友非成员函数没有对内部类的特权访问.因此,对非成员非成员使用成员函数会削弱类的封装.
这甚至不会让经验丰富
(资料来源:Herb Sutter的本周在线大师#84:http://www.gotw.ca/gotw/084.htm)
Jas*_*ock 118
我认为有些隐藏的一种语言功能,因为我在学校的整个过程中从未听说过它,是名称空间别名.直到我在boost文档中遇到它的例子之后才引起我的注意.当然,现在我了解它,你可以在任何标准的C++参考中找到它.
namespace fs = boost::filesystem;
fs::path myPath( strPath, fs::native );
Run Code Online (Sandbox Code Playgroud)
Joh*_*itb 102
变量不仅可以在for循环的init部分声明,还可以声明类和函数.
for(struct { int a; float b; } loop = { 1, 2 }; ...; ...) {
...
}
Run Code Online (Sandbox Code Playgroud)
这允许多个不同类型的变量.
Col*_*sen 77
数组运算符是关联的.
A [8]是*(A + 8)的同义词.由于加法是关联的,可以改写为*(8 + A),这是..... 8 [A]的同义词
你没说有用...... :-)
Joh*_*itb 73
有一点鲜为人知的是,工会也可以是模板:
template<typename From, typename To>
union union_cast {
From from;
To to;
union_cast(From from)
:from(from) { }
To getTo() const { return to; }
};
Run Code Online (Sandbox Code Playgroud)
他们也可以拥有构造函数和成员函数.没有任何与继承(包括虚函数)有关的事情.
Joh*_*itb 66
另一个在C中不起作用的隐藏功能是一元运算+符的功能.你可以用它来促进和腐朽各种各样的事物
+AnEnumeratorValue
Run Code Online (Sandbox Code Playgroud)
以前具有枚举类型的枚举器值现在具有可以适合其值的完美整数类型.手动,你很难知道那种类型!例如,当您想为枚举实现重载运算符时,需要这样做.
您必须使用一个使用类内静态初始化程序而没有类外定义的类,但有时它无法链接?操作员可以帮助创建一个临时的,而不会对其类型产生任何假设或依赖
struct Foo {
static int const value = 42;
};
// This does something interesting...
template<typename T>
void f(T const&);
int main() {
// fails to link - tries to get the address of "Foo::value"!
f(Foo::value);
// works - pass a temporary value
f(+Foo::value);
}
Run Code Online (Sandbox Code Playgroud)
你想将两个指针传递给一个函数,但它只是不起作用?操作员可以提供帮助
// This does something interesting...
template<typename T>
void f(T const& a, T const& b);
int main() {
int a[2];
int b[3];
f(a, b); // won't work! different values for "T"!
f(+a, +b); // works! T is "int*" both time
}
Run Code Online (Sandbox Code Playgroud)
MSN*_*MSN 61
与const引用相关的临时工的生命期是很少有人知道的.或者至少它是我最喜欢的C++知识,大多数人都不知道.
const MyClass& x = MyClass(); // temporary exists as long as x is in scope
Run Code Online (Sandbox Code Playgroud)
viv*_*dos 52
一个不常用的好功能是功能范围的try-catch块:
int Function()
try
{
// do something here
return 42;
}
catch(...)
{
return -1;
}
Run Code Online (Sandbox Code Playgroud)
主要用法是将异常转换为其他异常类和重新抛出,或者在异常和基于返回的错误代码处理之间进行转换.
Joh*_*itb 44
很多人都知道identity/ idmetafunction,但对于非模板情况,它有一个很好的用例:轻松编写声明:
// void (*f)(); // same
id<void()>::type *f;
// void (*f(void(*p)()))(int); // same
id<void(int)>::type *f(id<void()>::type *p);
// int (*p)[2] = new int[10][2]; // same
id<int[2]>::type *p = new int[10][2];
// void (C::*p)(int) = 0; // same
id<void(int)>::type C::*p = 0;
Run Code Online (Sandbox Code Playgroud)
它有助于大大解密C++声明!
// boost::identity is pretty much the same
template<typename T>
struct id { typedef T type; };
Run Code Online (Sandbox Code Playgroud)
Joh*_*itb 43
一个非常隐蔽的功能是您可以在if条件中定义变量,其范围将仅跨越if和else块:
if(int * p = getPointer()) {
// do something
}
Run Code Online (Sandbox Code Playgroud)
一些宏使用它,例如提供一些像这样的"锁定"范围:
struct MutexLocker {
MutexLocker(Mutex&);
~MutexLocker();
operator bool() const { return false; }
private:
Mutex &m;
};
#define locked(mutex) if(MutexLocker const& lock = MutexLocker(mutex)) {} else
void someCriticalPath() {
locked(myLocker) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
BOOST_FOREACH也在引擎盖下使用它.要完成此操作,不仅可以在if中,还可以在switch中:
switch(int value = getIt()) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
并在一个循环中:
while(SomeThing t = getSomeThing()) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
(也适用于条件).但我不太确定这些是否都有用:)
Joh*_*itb 29
有时您可以有效地使用逗号运算符,但是您希望确保没有用户定义的逗号运算符妨碍,因为例如您依赖于左侧和右侧之间的序列点,或者希望确保没有任何干扰所需的行动.这是void()进入游戏的地方:
for(T i, j; can_continue(i, j); ++i, void(), ++j)
do_code(i, j);
Run Code Online (Sandbox Code Playgroud)
忽略我为条件和代码提出的占位符.重要的是void(),它使编译器强制使用内置逗号运算符.这在实现traits类时也很有用,有时候也是如此.
Poo*_*rna 28
构造函数中的数组初始化.例如,在类中,如果我们有一个数组int:
class clName
{
clName();
int a[10];
};
Run Code Online (Sandbox Code Playgroud)
我们可以在构造函数中将数组中的所有元素初始化为其默认值(此处数组的所有元素为零):
clName::clName() : a()
{
}
Run Code Online (Sandbox Code Playgroud)
Rob*_*ert 27
哦,我可以提出一个宠物仇恨列表:
从积极的一面
Joh*_*itb 27
您可以访问任何类的受保护数据和函数成员,没有未定义的行为,并具有预期的语义.继续阅读,看看如何.另请阅读有关此问题的缺陷报告.
通常,C++禁止您访问类对象的非静态受保护成员,即使该类是您的基类
struct A {
protected:
int a;
};
struct B : A {
// error: can't access protected member
static int get(A &x) { return x.a; }
};
struct C : A { };
Run Code Online (Sandbox Code Playgroud)
那是被禁止的:你和编译器不知道引用实际指向的是什么.它可能是一个C对象,在这种情况下,类B没有业务和关于其数据的线索.只有x在对派生类或从派生类派生的类的引用时,才会授予此类访问权限.并且它可以允许任意一段代码通过组成一个读取成员的"丢弃"类来读取任何受保护的成员,例如std::stack:
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
static std::deque<int> &get(std::stack<int> &s) {
// error: stack<int>::c is protected
return s.c;
}
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = pillager::get(s);
}
Run Code Online (Sandbox Code Playgroud)
当然,正如你所看到的那样会造成太大的伤害.但现在,成员指针允许绕过这种保护!关键点是成员指针的类型绑定到实际包含所述成员的类- 而不是您在获取地址时指定的类.这允许我们规避检查
struct A {
protected:
int a;
};
struct B : A {
// valid: *can* access protected member
static int get(A &x) { return x.*(&B::a); }
};
struct C : A { };
Run Code Online (Sandbox Code Playgroud)
当然,它也适用于这个std::stack例子.
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
static std::deque<int> &get(std::stack<int> &s) {
return s.*(pillager::c);
}
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = pillager::get(s);
}
Run Code Online (Sandbox Code Playgroud)
使用派生类中的using声明会更容易,这会使成员名称为public并引用基类的成员.
void f(std::stack<int> &s) {
// now, let's decide to mess with that stack!
struct pillager : std::stack<int> {
using std::stack<int>::c;
};
// haha, now let's inspect the stack's middle elements!
std::deque<int> &d = s.*(&pillager::c);
}
Run Code Online (Sandbox Code Playgroud)
Sum*_*ant 26
隐藏功能:
如果函数抛出未在其异常规范中列出的异常,但该函数std::bad_exception在其异常规范中有异常,则会std::bad_exception自动转换并抛出异常.这样你至少会知道a bad_exception被扔了.在这里阅读更多.
功能尝试块
模板关键字在类模板中消除typedef的歧义.如果成员模板特的名字出现后.,->或::运营商,这个名字有明确限定的模板参数,以关键字template前缀的成员模板名称.在这里阅读更多.
函数参数默认值可以在运行时更改.在这里阅读更多.
A[i] 工作得很好 i[A]
可以修改类的临时实例!可以在临时对象上调用非const成员函数.例如:
struct Bar {
void modify() {}
}
int main (void) {
Bar().modify(); /* non-const function invoked on a temporary. */
}
Run Code Online (Sandbox Code Playgroud)
在这里阅读更多.
如果:在ternary(?:)运算符表达式之前和之后存在两种不同的类型,则表达式的结果类型是两者中最常用的类型.例如:
void foo (int) {}
void foo (double) {}
struct X {
X (double d = 0.0) {}
};
void foo (X) {}
int main(void) {
int i = 1;
foo(i ? 0 : 0.0); // calls foo(double)
X x;
foo(i ? 0.0 : x); // calls foo(X)
}
Run Code Online (Sandbox Code Playgroud)Joh*_*itb 26
另一个隐藏的功能是您可以调用可以转换为函数指针或引用的类对象.对它们的结果进行重载分辨率,并且完全转发参数.
template<typename Func1, typename Func2>
class callable {
Func1 *m_f1;
Func2 *m_f2;
public:
callable(Func1 *f1, Func2 *f2):m_f1(f1), m_f2(f2) { }
operator Func1*() { return m_f1; }
operator Func2*() { return m_f2; }
};
void foo(int i) { std::cout << "foo: " << i << std::endl; }
void bar(long il) { std::cout << "bar: " << il << std::endl; }
int main() {
callable<void(int), void(long)> c(foo, bar);
c(42); // calls foo
c(42L); // calls bar
}
Run Code Online (Sandbox Code Playgroud)
这些被称为"代理呼叫功能".
Con*_*tin 24
map::operator[]如果缺少键则创建条目并返回对缺省构造的条目值的引用.所以你可以写:
map<int, string> m;
string& s = m[42]; // no need for map::find()
if (s.empty()) { // assuming we never store empty values in m
s.assign(...);
}
cout << s;
Run Code Online (Sandbox Code Playgroud)
我很惊讶有多少C++程序员不知道这一点.
Özg*_*gür 19
在类模板中定义普通的朋友函数需要特别注意:
template <typename T>
class Creator {
friend void appear() { // a new function ::appear(), but it doesn't
… // exist until Creator is instantiated
}
};
Creator<void> miracle; // ::appear() is created at this point
Creator<double> oops; // ERROR: ::appear() is created a second time!
Run Code Online (Sandbox Code Playgroud)
在此示例中,两个不同的实例创建两个相同的定义 - 直接违反ODR
因此,我们必须确保类模板的模板参数出现在该模板中定义的任何友元函数的类型中(除非我们想要阻止特定文件中多个类模板的实例化,但这是不太可能的).让我们将其应用于前一个示例的变体:
template <typename T>
class Creator {
friend void feed(Creator<T>*){ // every T generates a different
… // function ::feed()
}
};
Creator<void> one; // generates ::feed(Creator<void>*)
Creator<double> two; // generates ::feed(Creator<double>*)
Run Code Online (Sandbox Code Playgroud)
免责声明:我已经从C++模板:完整指南 /第8.4 节粘贴了这一部分
Joh*_*itb 18
鲜为人知,但下面的代码很好
void f() { }
void g() { return f(); }
Run Code Online (Sandbox Code Playgroud)
以及下面奇怪的一个
void f() { return (void)"i'm discarded"; }
Run Code Online (Sandbox Code Playgroud)
了解这一点,你可以在某些方面利用.一个例子:void函数不能返回一个值,但你也不能只返回任何值,因为它们可以用非void实例化.不是将值存储到将导致错误的局部变量中,而是void直接返回值
template<typename T>
struct sample {
// assume f<T> may return void
T dosomething() { return f<T>(); }
// better than T t = f<T>(); /* ... */ return t; !
};
Run Code Online (Sandbox Code Playgroud)
Jas*_*ker 17
将文件读入字符串向量:
vector<string> V;
copy(istream_iterator<string>(cin), istream_iterator<string>(),
back_inserter(V));
Run Code Online (Sandbox Code Playgroud)
Ecl*_*pse 14
任何编程语言中最有趣的语法之一.
这些东西中的三个属于一起,两个是完全不同的东西......
SomeType t = u;
SomeType t(u);
SomeType t();
SomeType t;
SomeType t(SomeType(u));
Run Code Online (Sandbox Code Playgroud)
除了第三个和第五个之外的所有SomeType对象都在堆栈上定义并初始化它(u在前两种情况下,在第四种情况下使用默认构造函数.第三种是声明一个不带参数并返回a的函数SomeType.第五种类似于声明一个函数,它通过SomeType命名类型的值获取一个参数u.
Kaz*_*gon 14
您可以模板位域.
template <size_t X, size_t Y>
struct bitfield
{
char left : X;
char right : Y;
};
Run Code Online (Sandbox Code Playgroud)
我还没有为此提出任何目的,但确实让我感到惊讶.
Aar*_*reP 12
摆脱前瞻性声明:
struct global
{
void main()
{
a = 1;
b();
}
int a;
void b(){}
}
singleton;
Run Code Online (Sandbox Code Playgroud)
用?:运算符编写switch语句:
string result =
a==0 ? "zero" :
a==1 ? "one" :
a==2 ? "two" :
0;
Run Code Online (Sandbox Code Playgroud)
在一条线上做所有事情:
void a();
int b();
float c = (a(),b(),1.0f);
Run Code Online (Sandbox Code Playgroud)
没有memset的结构清零:
FStruct s = {0};
Run Code Online (Sandbox Code Playgroud)
标准化/包装角度和时间值:
int angle = (short)((+180+30)*65536/360) * 360/65536; //==-150
Run Code Online (Sandbox Code Playgroud)
分配参考:
struct ref
{
int& r;
ref(int& r):r(r){}
};
int b;
ref a(b);
int c;
*(int**)&a = &c;
Run Code Online (Sandbox Code Playgroud)
AnT*_*AnT 12
三元条件运算符?:要求其第二和第三操作数具有"令人愉快"的类型(非正式地说).但是这个要求有一个例外(双关语):第二个或第三个操作数可以是一个throw表达式(有类型void),而不管另一个操作数的类型.
换句话说,可以使用?:运算符编写以下有效的C++表达式
i = a > b ? a : throw something();
Run Code Online (Sandbox Code Playgroud)
BTW,throw表达式实际上是一个表达式(类型void)而不是语句这一事实是C++语言的另一个鲜为人知的特性.这意味着,以下代码完全有效
void foo()
{
return throw something();
}
Run Code Online (Sandbox Code Playgroud)
虽然这样做没有多大意义(可能在一些通用的模板代码中,这可能会派上用场).
Joh*_*itb 12
优势规则很有用,但鲜为人知.它表示即使在通过基类网格的非唯一路径中,如果成员属于虚拟基类,则部分隐藏成员的名称查找也是唯一的:
struct A { void f() { } };
struct B : virtual A { void f() { cout << "B!"; } };
struct C : virtual A { };
// name-lookup sees B::f and A::f, but B::f dominates over A::f !
struct D : B, C { void g() { f(); } };
Run Code Online (Sandbox Code Playgroud)
我已经用它来实现对齐支持,通过优势规则自动找出最严格的对齐方式.
这不仅适用于虚函数,还适用于typedef名称,静态/非虚拟成员等.我已经看到它曾用于在元程序中实现可重写的特性.
小智 8
一个危险的秘密是
Fred* f = new(ram) Fred(); http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10
f->~Fred();
Run Code Online (Sandbox Code Playgroud)
我很少看到我最喜欢的秘密:
class A
{
};
struct B
{
A a;
operator A&() { return a; }
};
void func(A a) { }
int main()
{
A a, c;
B b;
a=c;
func(b); //yeah baby
a=b; //gotta love this
}
Run Code Online (Sandbox Code Playgroud)
本地课程很棒:
struct MyAwesomeAbstractClass
{ ... };
template <typename T>
MyAwesomeAbstractClass*
create_awesome(T param)
{
struct ans : MyAwesomeAbstractClass
{
// Make the implementation depend on T
};
return new ans(...);
}
Run Code Online (Sandbox Code Playgroud)
非常整洁,因为它没有用无用的类定义污染命名空间......
小智 7
原始类型具有构造函数.
int i(3);
Run Code Online (Sandbox Code Playgroud)
作品.
一个隐藏的功能,甚至是GCC开发人员隐藏的功能,是使用字符串文字初始化数组成员.假设您有一个需要使用C数组的结构,并且您希望使用默认内容初始化该数组成员
struct Person {
char name[255];
Person():name("???") { }
};
Run Code Online (Sandbox Code Playgroud)
这有效,并且只适用于char数组和字符串文字初始值设定项.不需要strcpy!
小智 6
许多例子中的一个例子:模板元编程.标准委员会中没有人打算在编译时执行图灵完整的子语言.
模板元编程几乎不是隐藏的功能.它甚至在升级库中.见MPL.但如果"几乎隐藏"足够好,那么看一下boost库.它包含许多好东西,没有强大的库的支持,不容易访问.
一个例子是boost.lambda库,这很有趣,因为C++在当前标准中没有lambda函数.
另一个例子是Loki,它"广泛使用C++模板元编程并实现了几种常用的工具:类型列表,仿函数,单例,智能指针,对象工厂,访问者和多方法." [ 维基百科 ]
没有隐藏的功能,但C++语言非常强大,甚至标准的开发人员也无法想象C++可以用于什么.
实际上,从简单的语言构造,你可以写出非常强大的东西.很多这样的东西可以在www.boost.org上找到(例如http://www.boost.org/doc/libs/1_36_0/doc/html/lambda.html).
为了理解简单的语言结构如何与强大的东西结合起来,最好阅读David Vandevoorde,Nicolai M. Josuttis撰写的" C++模板:完整指南",以及Andrei Alexandrescu的真实魔法书"现代C++设计......".
最后,学习C++很难,你应该尝试填充它;)
| 归档时间: |
|
| 查看次数: |
78280 次 |
| 最近记录: |