C++11:通用为本,专用为末(三)

2014-11-24 07:13:38 · 作者: · 浏览: 1
1中可以通过设定一个后缀标识的操作符,将声明了该后缀的字面量转换为需要的类型。这在编写测试用例的时候,常会遇见声明较多的值去初始化一个对象,现在对象可以像内置类型那样传递字面常量,从而不需要声明过多的值。

#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;
}//拷贝构造和非显示类型转换都不被允许,不能通过赋值表达式或者函数参数的方式获得一个目标类型