当前位置:  开发笔记 > 编程语言 > 正文

C++的隐藏功能?

如何解决《C++的隐藏功能?》经验,为你挑选了37个好方法。

当涉及到"问题线"的"隐藏特征"时,没有C++的爱吗?想我会把它扔出去.C++的一些隐藏功能是什么?



1> Ferruccio..:

大多数C++程序员都熟悉三元运算符:

x = (y < 0) ? 10 : 20;

但是,他们没有意识到它可以用作左值:

(a == 0 ? a : b) = 1;

这是简写

if (a == 0)
    a = 1;
else
    b = 1;

谨慎使用:-)


让人惊讶.(a == 0?a:b)=(y <0?10:20);
(b?trueCount:falseCount)++
Dunno如果它是GCC特定的,但我很惊讶地发现这也有效:`(value?function1:function2)()`.
很有意思.我可以看到制作一些不可读的代码.
@Chris Burt-Brown:不,如果它们具有相同的类型(即没有默认参数),它应该在任何地方工作.`function1`和`function2`被隐含地转换为函数指针,并且结果被隐式转换回来.

2> 小智..:

您可以将URI放入C++源代码而不会出错.例如:

void foo() {
    http://stackoverflow.com/
    int bar = 4;

    ...
}


@jpoh:http跟随冒号成为"标签",稍后您将在goto语句中使用它.你从编译器得到警告,因为它没有在上面例子中的任何goto语句中使用.
但我怀疑每个功能只有一个?:)
只要具有不同的协议,您就可以添加多个!ftp://ftp.microsoft.com gopher://aerv.nl/1等等......
不幸的是`goto http;`实际上并不遵循URL.:(
@Pavel:后跟冒号的标识符是一个标签(用于`goto`,C++确实有).跟随两个斜杠的任何内容都是评论.因此,使用`http:// stackoverflow.com`,`http`是一个标签(理论上你可以写`goto http;`),而`// stackoverflow.com`只是一个行尾注释.这两个都是合法的C++,所以构造编译.当然,它没有做任何模糊的用处.
只是不要尝试为每个源文件添加多个:P

3> 小智..:

指针算术.

由于可以引入的错误,C++程序员更喜欢避免使用指针.

我见过的最酷的C++?模拟文字.


我们因为bug而避免使用指针?指针基本上是动态C++编码的一切!

4> paercebal..:

我同意那里的大多数帖子: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)


伟大的帖子,+1特别是最后一部分,很少有人意识到.我可能会将Boost库添加为"隐藏功能".我几乎认为它是C++应该拥有的标准库.;)

5> Jason Mock..:

我认为有些隐藏的一种语言功能,因为我在学校的整个过程中从未听说过它,是名称空间别名.直到我在boost文档中遇到它的例子之后才引起我的注意.当然,现在我了解它,你可以在任何标准的C++参考中找到它.

namespace fs = boost::filesystem;

fs::path myPath( strPath, fs::native );


它也可以作为在实现之间切换的一种方式,无论是选择线程安全还是非线程安全,还是选择版本1与2.
如果您正在处理具有大型命名空间层次结构的非常大的项目并且您不希望标题导致命名空间污染(并且您希望您的变量声明是人类可读的),那么它尤其有用.

6> Johannes Sch..:

变量不仅可以在for循环的init部分声明,还可以声明类和函数.

for(struct { int a; float b; } loop = { 1, 2 }; ...; ...) {
    ...
}

这允许多个不同类型的变量.


很高兴知道你可以做到,但我个人真的试图避免做那样的事情.主要是因为它很难阅读.
实际上,在这种情况下可以使用一对:for(std :: pair loop = std :: make_pair(1,2); loop.first> 0; loop.second + = 1)
@Valentin然后我建议你尝试对VS2008进行bug报告,而不是低估隐藏的功能.这显然是编译器的错误.
嗯,它在msvc10中也不起作用.多么悲伤 :(
@avakar事实上,gcc引入了一个让它拒绝的错误,在v4.6 :)请参阅http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46791

7> Colin Jensen..:

数组运算符是关联的.

A [8]是*(A + 8)的同义词.由于加法是关联的,可以改写为*(8 + A),这是..... 8 [A]的同义词

你没说有用...... :-)


你的意思是"交换",你说"联想"?
文森特,你错了."A"的类型根本不重要.例如,如果`A`是`char*`,代码仍然有效.
实际上,在使用这个技巧时,你应该注意你使用的是什么类型.A [8]实际上是第8个A而8 [A]是从地址8开始的Ath整数.如果A是一个字节,则有一个错误.
文森特,在这里必须有一个整体类型和一个指针类型,C和C++都不关心哪一个先行.
请注意A必须是指针,而不是类重载operator [].
A [8]评估为"*(A + 8)".8 [A]评估为"*(8 + A)".他们是一样的.

8> Johannes Sch..:

有一点鲜为人知的是,工会也可以是模板:

template
union union_cast {
    From from;
    To   to;

    union_cast(From from)
        :from(from) { }

    To getTo() const { return to; }
};

他们也可以拥有构造函数和成员函数.没有任何与继承(包括虚函数)有关的事情.


@gbacon,是的,如果设置并使用`From`和`To`,它会调用未定义的行为.这样的联合可以用于定义的行为(使用`To`是unsigned char数组或者一个struct与`From`共享一个初始序列).即使您以未定义的方式使用它,它仍可能对低级别的工作有用.无论如何,这只是联合模板的一个例子 - 模板联合可能还有其他用途.
小心构造函数.请注意,您只需要构造第一个元素,并且只允许在C++ 0x中使用它.从目前的标准来看,你必须坚持简单的可构造类型.没有破坏者.

9> Konrad Rudol..:

C++是一个标准,不应该有任何隐藏的功能......

C++是一种多范式语言,你可以把最后的钱押在那里隐藏的功能.许多例子中的一个例子:模板元编程.标准委员会中没有人打算在编译时执行图灵完整的子语言.



10> Johannes Sch..:

另一个在C中不起作用的隐藏功能是一元运算+符的功能.你可以用它来促进和腐朽各种各样的事物

将枚举转换为整数

+AnEnumeratorValue

以前具有枚举类型的枚举器值现在具有可以适合其值的完美整数类型.手动,你很难知道那种类型!例如,当您想为枚举实现重载运算符时,需要这样做.

从变量中获取值

您必须使用一个使用类内静态初始化程序而没有类外定义的类,但有时它无法链接?操作员可以帮助创建一个临时的,而不会对其类型产生任何假设或依赖

struct Foo {
  static int const value = 42;
};

// This does something interesting...
template
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);
}

将数组衰减到指针

你想将两个指针传递给一个函数,但它只是不起作用?操作员可以提供帮助

// This does something interesting...
template
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
}



11> MSN..:

与const引用相关的临时工的生命期是很少有人知道的.或者至少它是我最喜欢的C++知识,大多数人都不知道.

const MyClass& x = MyClass(); // temporary exists as long as x is in scope


ScopeGuard(http://www.ddj.com/cpp/184403758)是一个利用此功能的好例子.
你能详细说说吗?因为你只是戏弄;)
我和Joseph Garvin在一起.请指教我们.

12> vividos..:

一个不常用的好功能是功能范围的try-catch块:

int Function()
try
{
   // do something here
   return 42;
}
catch(...)
{
   return -1;
}

主要用法是将异常转换为其他异常类和重新抛出,或者在异常和基于返回的错误代码处理之间进行转换.


返回仅对构造函数禁止.构造函数的函数try块将捕获初始化基类和成员的错误(函数try块执行的操作与在函数内部尝试不同的唯一情况); 不重新投掷会导致不完整的对象.
正如@puetzk所指出的,这是在构造函数的**初始化列表**中处理由***抛出的异常的唯一方法,例如基类的构造函数或数据成员的构造函数.

13> Johannes Sch..:

很多人都知道identity/ idmetafunction,但对于非模板情况,它有一个很好的用例:轻松编写声明:

// void (*f)(); // same
id::type *f;

// void (*f(void(*p)()))(int); // same
id::type *f(id::type *p);

// int (*p)[2] = new int[10][2]; // same
id::type *p = new int[10][2];

// void (C::*p)(int) = 0; // same
id::type C::*p = 0;

它有助于大大解密C++声明!

// boost::identity is pretty much the same
template 
struct id { typedef T type; };



14> Johannes Sch..:

一个非常隐蔽的功能是您可以在if条件中定义变量,其范围将仅跨越if和else块:

if(int * p = getPointer()) {
    // do something
}

一些宏使用它,例如提供一些像这样的"锁定"范围:

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) { /* ... */ }
}

BOOST_FOREACH也在引擎盖下使用它.要完成此操作,不仅可以在if中,还可以在switch中:

switch(int value = getIt()) {
    // ...
}

并在一个循环中:

while(SomeThing t = getSomeThing()) {
    // ...
}

(也适用于条件).但我不太确定这些是否都有用:)


非常好,除非你没有提到这个功能的用途是用于动态指针转换,我相信.
@Frerich,这在C代码中是不可能的.我想你正在考虑`if((a = f())== b)......`,但这个答案实际上是在条件中声明了一个变量.

15> Johannes Sch..:

防止逗号运算符调用运算符重载

有时您可以有效地使用逗号运算符,但是您希望确保没有用户定义的逗号运算符妨碍,因为例如您依赖于左侧和右侧之间的序列点,或者希望确保没有任何干扰所需的行动.这是void()进入游戏的地方:

for(T i, j; can_continue(i, j); ++i, void(), ++j)
  do_code(i, j);

忽略我为条件和代码提出的占位符.重要的是void(),它使编译器强制使用内置逗号运算符.这在实现traits类时也很有用,有时候也是如此.



16> Poorna..:

构造函数中的数组初始化.例如,在类中,如果我们有一个数组int:

class clName
{
  clName();
  int a[10];
};

我们可以在构造函数中将数组中的所有元素初始化为其默认值(此处数组的所有元素为零):

clName::clName() : a()
{
}


你可以在任何地方使用任何数组.

17> Robert..:

哦,我可以提出一个宠物仇恨列表:

如果您打算使用多态,则析构函数必须是虚拟的

有时会默认初始化成员,有时则不会

本地clases不能用作模板参数(使它们不那么有用)

异常说明符:看起来很有用,但不是

函数重载隐藏具有不同签名的基类函数.

国际化没有有用的标准化(便携式标准宽字符集,任何人?我们必须等到C++ 0x)

从积极的一面

隐藏功能:功能尝试块.不幸的是我没有找到它的用途.是的我知道为什么他们添加它,但你必须重新抛出一个构造函数,这使它毫无意义.

在容器修改之后,值得仔细查看STL保证迭代器有效性,这可以让你做一些稍好的循环.

提升 - 这不是什么秘密,但它值得使用.

返回值优化(不明显,但标准特别允许)

Functors aka function objects aka operator().这被STL广泛使用.不是真正的秘密,但是操作符重载和模板的一个漂亮的副作用.


宠物仇恨:C++应用程序没有定义的ABI,不像每个人使用的C语言,因为每种语言都可以保证调用C函数,没有人可以为C++做同样的事情.
只有当你打算多态破坏时,析构函数才需要是虚拟的,这与第一点略有不同.
使用C++ 0x本地类型可以用作模板参数.

18> Johannes Sch..:

您可以访问任何类的受保护数据和函数成员,没有未定义的行为,并具有预期的语义.继续阅读,看看如何.另请阅读有关此问题的缺陷报告.

通常,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 { };

那是被禁止的:你和编译器不知道引用实际指向的是什么.它可能是一个C对象,在这种情况下,类B没有业务和关于其数据的线索.只有x在对派生类或从派生类派生的类的引用时,才会授予此类访问权限.并且它可以允许任意一段代码通过组成一个读取成员的"丢弃"类来读取任何受保护的成员,例如std::stack:

void f(std::stack &s) {
    // now, let's decide to mess with that stack!
    struct pillager : std::stack {
        static std::deque &get(std::stack &s) {
            // error: stack::c is protected
            return s.c;
        }
    };

    // haha, now let's inspect the stack's middle elements!
    std::deque &d = pillager::get(s);
}

当然,正如你所看到的那样会造成太大的伤害.但现在,成员指针允许绕过这种保护!关键点是成员指针的类型绑定到实际包含所述成员的类- 而不是您在获取地址时指定的类.这允许我们规避检查

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 { };

当然,它也适用于这个std::stack例子.

void f(std::stack &s) {
    // now, let's decide to mess with that stack!
    struct pillager : std::stack {
        static std::deque &get(std::stack &s) {
            return s.*(pillager::c);
        }
    };

    // haha, now let's inspect the stack's middle elements!
    std::deque &d = pillager::get(s);
}

使用派生类中的using声明会更容易,这会使成员名称为public并引用基类的成员.

void f(std::stack &s) {
    // now, let's decide to mess with that stack!
    struct pillager : std::stack {
        using std::stack::c;
    };

    // haha, now let's inspect the stack's middle elements!
    std::deque &d = s.*(&pillager::c);
}



19> Sumant..:

隐藏功能:

    纯虚函数可以实现.常见的例子,纯虚拟析构函数.

    如果函数抛出未在其异常规范中列出的异常,但该函数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. */
    }
    

    在这里阅读更多.

    如果:在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)
    }
    


关于你的第一点:有一个特殊情况,你必须*实现一个纯虚函数:纯虚拟析构函数.

20> Johannes Sch..:

另一个隐藏的功能是您可以调用可以转换为函数指针或引用的类对象.对它们的结果进行重载分辨率,并且完全转发参数.

template
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 c(foo, bar);
  c(42); // calls foo
  c(42L); // calls bar
}

这些被称为"代理呼叫功能".


@navigator,是的,它从概念上转换为两者,然后选择最好的.它不需要实际调用它们,因为它从结果类型中知道它们已经产生了什么.实际调用是在最终选择的内容时完成的.

21> Constantin..:

map::operator[]如果缺少键则创建条目并返回对缺省构造的条目值的引用.所以你可以写:

map 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;

我很惊讶有多少C++程序员不知道这一点.


而在另一端,你不能在const映射上使用operator []
尼克+1,如果他们不知道`.find()`,人们会疯了.
它不是该语言的一项功能,而是标准模板库的一项功能.这也很明显,因为operator []返回一个有效的引用.
我必须在C#中使用地图,而地图不会那样,以便意识到这是一个功能.我以为我比它使用它更烦恼,但似乎我错了.我在C#中错过了它.

22> Jim Hunziker..:

将函数或变量放在无名称命名空间中不赞成使用static它们来限制它们到文件范围.



23> Özgür..:

在类模板中定义普通的朋友函数需要特别注意:

template  
class Creator { 
    friend void appear() {  // a new function ::appear(), but it doesn't 
        …                   // exist until Creator is instantiated 
    } 
};
Creator miracle;  // ::appear() is created at this point 
Creator oops;   // ERROR: ::appear() is created a second time! 

在此示例中,两个不同的实例创建两个相同的定义 - 直接违反ODR

因此,我们必须确保类模板的模板参数出现在该模板中定义的任何友元函数的类型中(除非我们想要阻止特定文件中多个类模板的实例化,但这是不太可能的).让我们将其应用于前一个示例的变体:

template  
class Creator { 
    friend void feed(Creator*){  // every T generates a different 
        …                           // function ::feed() 
    } 
}; 

Creator one;     // generates ::feed(Creator*) 
Creator two;   // generates ::feed(Creator*) 

免责声明:我已经从C++模板:完整指南 /第8.4 节粘贴了这一部分



24> Johannes Sch..:

void函数可以返回void值

鲜为人知,但下面的代码很好

void f() { }
void g() { return f(); }

以及下面奇怪的一个

void f() { return (void)"i'm discarded"; }

了解这一点,你可以在某些方面利用.一个例子:void函数不能返回一个值,但你也不能只返回任何值,因为它们可以用非void实例化.不是将值存储到将导致错误的局部变量中,而是void直接返回值

template
struct sample {
  // assume f may return void
  T dosomething() { return f(); }

  // better than T t = f(); /* ... */ return t; !
};



25> Jason Baker..:

将文件读入字符串向量:

 vector V;
 copy(istream_iterator(cin), istream_iterator(),
     back_inserter(V));

istream_iterator


或者:vector V((istream_iterator (cin)),istream_iterator );
你的意思是`vector V((istream_iterator (cin)),istream_iterator ());` - 第二个参数后缺少括号

26> Eclipse..:

任何编程语言中最有趣的语法之一.

这些东西中的三个属于一起,两个是完全不同的东西......

SomeType t = u;
SomeType t(u);
SomeType t();
SomeType t;
SomeType t(SomeType(u));

除了第三个和第五个之外的所有SomeType对象都在堆栈上定义并初始化它(u在前两种情况下,在第四种情况下使用默认构造函数.第三种是声明一个不带参数并返回a的函数SomeType.第五种类似于声明一个函数,它通过SomeType命名类型的值获取一个参数u.


第一个是构造函数的隐式调用,第二个是显式调用.查看以下代码以查看区别:#include class sss {public:explicit sss(int){std :: cout <<"int"<< std :: endl; }; sss(double){std :: cout <<"double"<< std :: endl; }; }; int main(){sss ddd(7); //调用int构造函数sss xxx = 7; //调用double构造函数返回0; }

27> Kaz Dragon..:

您可以模板位域.

template 
struct bitfield
{
    char left  : X;
    char right : Y;
};

我还没有为此提出任何目的,但确实让我感到惊讶.



28> AareP..:

摆脱前瞻性声明:

struct global
{
     void main()
     {
           a = 1;
           b();
     }
     int a;
     void b(){}
}
singleton;

用?:运算符编写switch语句:

string result = 
    a==0 ? "zero" :
    a==1 ? "one" :
    a==2 ? "two" :
    0;

在一条线上做所有事情:

void a();
int b();
float c = (a(),b(),1.0f);

没有memset的结构清零:

FStruct s = {0};

标准化/包装角度和时间值:

int angle = (short)((+180+30)*65536/360) * 360/65536; //==-150

分配参考:

struct ref
{
   int& r;
   ref(int& r):r(r){}
};
int b;
ref a(b);
int c;
*(int**)&a = &c;


`FStruct s = {};`甚至更短.
语法"float c =(a(),b(),1.0f);" 有助于强调分配操作("c"的分配).Assigment-operations在编程中很重要,因为它们不太可能成为IMO的弃用者.不知道为什么,可能与函数式编程有关,其中每帧重新分配程序状态.PS.不,"int d =(11,22,1.0f)"将等于"1".一分钟前用VS2008测试过.
+1你不应该_calling_`main`?我建议`global().main();`然后忘记单例(_你可以使用临时的,它可以使它的生命周期延长_)

29> AnT..:

三元条件运算符?:要求其第二和第三操作数具有"令人愉快"的类型(非正式地说).但是这个要求有一个例外(双关语):第二个或第三个操作数可以是一个throw表达式(有类型void),而不管另一个操作数的类型.

换句话说,可以使用?:运算符编写以下有效的C++表达式

i = a > b ? a : throw something();

BTW,throw表达式实际上是一个表达式(类型void)而不是语句这一事实是C++语言的另一个鲜为人知的特性.这意味着,以下代码完全有效

void foo()
{
  return throw something();
}

虽然这样做没有多大意义(可能在一些通用的模板代码中,这可能会派上用场).



30> Johannes Sch..:

优势规则很有用,但鲜为人知.它表示即使在通过基类网格的非唯一路径中,如果成员属于虚拟基类,则部分隐藏成员的名称查找也是唯一的:

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(); } };

我已经用它来实现对齐支持,通过优势规则自动找出最严格的对齐方式.

这不仅适用于虚函数,还适用于typedef名称,静态/非虚拟成员等.我已经看到它曾用于在元程序中实现可重写的特性.



31> Drealmer..:

我发现这个博客是一个关于C++:C++ Truths的神奇资源.



32> 小智..:

一个危险的秘密是

Fred* f = new(ram) Fred(); http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10
f->~Fred();

我很少看到我最喜欢的秘密:

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
}


嗯,不想这么说,但那实际上是一个不是很隐蔽的"类型演员".任何曾经看过运算符重载的人都可能知道这一点.

33> Alexandre C...:

本地课程很棒:

struct MyAwesomeAbstractClass
{ ... };


template 
MyAwesomeAbstractClass*
create_awesome(T param)
{
    struct ans : MyAwesomeAbstractClass
    {
        // Make the implementation depend on T
    };

    return new ans(...);
}

非常整洁,因为它没有用无用的类定义污染命名空间......



34> 小智..:

原始类型具有构造函数.

int i(3);

作品.


那不是构造函数,这只是一种初始化形式,即*直接初始化*.原始类型没有构造函数.

35> Johannes Sch..:

一个隐藏的功能,甚至是GCC开发人员隐藏的功能,是使用字符串文字初始化数组成员.假设您有一个需要使用C数组的结构,并且您希望使用默认内容初始化该数组成员

struct Person {
  char name[255];
  Person():name("???") { }
};

这有效,并且只适用于char数组和字符串文字初始值设定项.不需要strcpy!



36> 小智..:

许多例子中的一个例子:模板元编程.标准委员会中没有人打算在编译时执行图灵完整的子语言.

模板元编程几乎不是隐藏的功能.它甚至在升级库中.见MPL.但如果"几乎隐藏"足够好,那么看一下boost库.它包含许多好东西,没有强大的库的支持,不容易访问.

一个例子是boost.lambda库,这很有趣,因为C++在当前标准中没有lambda函数.

另一个例子是Loki,它"广泛使用C++模板元编程并实现了几种常用的工具:类型列表,仿函数,单例,智能指针,对象工厂,访问者和多方法." [ 维基百科 ]


模板元编程不再隐藏,因为它非常有用.然而,它隐藏在这个功能未被设计到C++中的方式中,而是巧妙地出现了.

37> sergtk..:

没有隐藏的功能,但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++很难,你应该尝试填充它;)

推荐阅读
放ch养奶牛
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有