#include
#include
using namespace std; typedef unsigned char uint8; struct RGBA{ uint8 r; uint8 g; uint8 b; uint8 a; RGBA(uint8 R, uint8 G, uint8 B, uint8 A = 0): r(R), g(G), b(B), a(A){} }; RGBA operator "" _C(const char* col, size_t n) {// 一个长度为n的字符串col,后缀标识_C的操作符,"" _C中间必须有空格 const char* p = col; const char* end = col + n; const char* r, *g, *b, *a; r = g = b = a = nullptr; for(; p != end; ++p) { if (*p == 'r') r = p; else if (*p == 'g') g = p; else if (*p == 'b') b = p; else if (*p == 'a') a = p; } if ((r == nullptr) || (g == nullptr) || (b == nullptr)) throw; else if (a == nullptr) return RGBA(atoi(r+1), atoi(g+1), atoi(b+1)); else return RGBA(atoi(r+1), atoi(g+1), atoi(b+1), atoi(b+1)); } std::ostream & operator << (std::ostream & out, RGBA & col) { return out << "r: " << (int)col.r << ", g: " << (int)col.g << ", b: " << (int)col.b << ", a: " << (int)col.a << endl; } void blend(RGBA && col1, RGBA && col2) { // Some color blending action cout << "blend " << endl << col1 << col2 << endl; } int main() { blend("r255 g240 b155"_C, "r15 g255 b10 a7"_C);//声明了_C的后缀标识符字面量转换为需要的类型,从而避免声明:RGB a(255,240,155),b(15,255,10,7);再传给blend(a,b); }
但是该规则要受限于字面量类型。
10 内联名字空间:C++11中通过inline namespace声明内联命名空间,内联命名空间允许父命名空间定义或特化子命名空间的模板。但是还是使用域限定符::简单安全些,内联命名空间太花哨了。
#include
using namespace std;
namespace Jim {
inline namespace Basic {
struct Knife{ Knife() { cout << "Knife in Basic." << endl; } };
class CorkScrew{};
}
inline namespace Toolkit {
template
class SwissArmyKnife{}; } // ... namespace Other{ Knife b; // Knife in Basic struct Knife{ Knife() { cout << "Knife in Other" << endl;} }; Knife c; // Knife in Other Basic::Knife k; // Knife in Basic } } // 这是LiLei在使用Jim的库 namespace Jim { template<> class SwissArmyKnife
{}; // 模板偏特化,编译通过 } using namespace Jim; int main() { SwissArmyKnife
sknife;//还是使用域限定符理解起来简单些,Toolkit::SwissArmyKnife
sknife; }
11 模板的别名:在C++11中using可以替代typedef的功能,尤其在使用模板 编程的时候using更加灵活。
template
using MapString=std::map
; MapString
numberString;//对MapString类型进行实例化
可以通过is_name模板类判断两个类型是否一致: is_name<类名1,类名2>::value, 若该值为1则表示两个类型是一样的,若该值为0则表明两个类型不同
12 SFINEA规则:substitution failure is not an error匹配失败不是错误,在针对重载的模板参数进行展开的时候,若果导致了一些类系那个不匹配编译器不会报错。
struct Test{
typedef int foo;
};
template
//第一个模板函数
void f(typename T::foo){}
template
//第二个模板函数 void f(T){} int main(){ f
(10);//第一个模板函数 f
(10);//调用第二个模板函数,但是在编译器匹配第一个的时候int::foo不会报错 }
在C++11中,对SFINAE一般化,尤其是模板参数替换时使用了表达式,若表达式没有使用外部于表达式本身的元素是不会导致SFINAE失败,如:
template
struct A{};
char xxx(int);
char xxx(float);
template
A(sizeof(xxx((T)0)> f(T){}//模板参数使用sizeof表达式,但是其没有使用超出表达式本身的元素 int main(){ f(1); return 0; }
13 显示转换操作符:C++11中,将explicit的使用范围扩展到了自定义的类型转换操作符上,以支持显示类型转换,explict作用在类型转换操作符上,意味着只有在直接构造或显示类型转换才可以使用该类型。
class ConvertTo {};
class Convertable {//定义了显示转换到ConvertTo类型的类型转换符,
public:
explicit operator ConvertTo () const { return ConvertTo(); }
//operator bool () const { return true; }
explicit operator bool () const { return true; }
};
void Func(ConvertTo ct) {}
void test() {
Convertable c;
ConvertTo ct(c); // 直接初始化,通过。 直接构造
ConvertTo ct2 = c; // 拷贝构造初始化,编译失败
ConvertTo ct3 = static_cast
(c); // 强制转化,通过。显示类型转换
Func(c); // 拷贝构造初始化,编译失败
if (c) {}//operator bool()
c + 1;
}//拷贝构造和非显示类型转换都不被允许,不能通过赋值表达式或者函数参数的方式获得一个目标类型