template 两个用途:
1.常见的在模板定义的开始,比如template<typename ...Args>
2.模板类内部定义了模板成员函数或者嵌套的成员模板类。比如:
template<typename ...Args>
class TeTest
{
public:
bool is()const
{
return true;
}
};
template<typename T>
class TeFunc
{
protected:
using Value = TeTest<T>;
Value value;
protected:
bool isValue()const
{
return value.template is();
}
};
//继承自stl中的容器 比如vector
template <typename T, template <typename> class Cont = std::vector>
class Test : public Cont<point<T>>
{
public:
};
限制模板形参类型
//方法一
template<typename T>
typename std::enable_if<std::is_integral<T>::value,bool>::type
is_inte(T i)
{
return bool(i % 2);
}
//方法二
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_oht(T i)
{
return bool(i%2);
}
1.static_assert
不同于assert,static_assert是在编译期就检查表达式为真或非零,而assert是在程序运行期才检查
static_assert(sizeof(void *) == 4, "64-bit code generation is not supported.");
2.不定参数模板
template<typename T>
void printT(T t)
{
cout << t << " ";
}
template<typename T, typename ...Args>
void printT(T t, Args ...args)
{
printT(t);
printT(args...);
}
template<typename ...Args>
void clacSize(Args ...args)
{
cout << "size:" << sizeof...(args) << endl;
}
int main()
{
printT(10,123,"hello world.");
cout << endl;
clacSize("hello"," world", 100, 10, 1);
}
output:
10 123 hello world.
size:5
3.元组(不同类型值的集合)
template<typename T>
void output(const T &t)
{
cout << t << endl;
}
template<typename T ,typename... Args>
void output(const T &a, Args... arg)
{
cout << a << endl;
output(arg...);
}
template<typename... T>
std::tuple<T...> getDD(T... aa)
{
return std::make_tuple(aa...);
}
template<typename TT,std::size_t N>
struct TuplePrinter{
static void print(const TT &value)
{
TuplePrinter<TT, N - 1>::print(value);
cout << "," << std::get<N-1>(value);
}
};
template<typename T>
struct TuplePrinter<T,1>{
static void print(const T &t)
{
cout << std::get<0>(t) ;
}
};
template<typename ... Args>
void PrintTuple(const std::tuple<Args...> &t)
{
TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
}
int main(void)
{
auto vv = getDD(10,11);
cout << "num = " << std::tuple_size<decltype(vv)>::value << endl;
output(std::get<0>(vv), std::get<1>(vv));
auto cc = std::tie("test","world");//
cout << std::get<0>(cc) << endl;
auto oo = std::tuple_cat(vv, cc);
PrintTuple(oo);
cout << endl;
return 0;
}
result:
num = 2
10
11
test
10,11,test,world
4.auto
自动推导
auto a = 12;auto b = 12.0f;auto c = true;auto d = [] (int x)->int{ return 12;};auto e = std::bind(&func, _1);
或者函数,可以根据传入类型,推导出函数返回类型
template <typename _Tx, typename _Ty> auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty) { return x*y; }
5.std::is_same std::is_convertible
std::is_same 是判断两个类型是否相等
std::is_convertible是拍单两个类型是否是继承关系
cout << std::is_same<int, char>::value;
result:0
class One
{
};http://write.blog.csdn.net/postedit/53640611
class Two : public One
{
};
cout << std::is_convertible<Two, One>::value << endl;
cout << std::is_convertible<One, Two>::value << endl;
result:
0
1
6.内存对齐
內存对齐的作用:
1. 平台原因(移植原因):不是所有的硬件凭条都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。由于CPU把内存当成是一块一块的,块的大小可以是2、4、8、16字节大小,因此CPU在读取内存时是一块
一块进行读取的。所以如果字节不对齐,有可能会出现比如一个int类型位于两块内存中,这样cpu就要读取两块,这就进行了额外的操作,大大降低了CPU的性能
alignas(4) char t;
alignas(int) char c;
cout << alignof(t) << endl;
alignas只能改大内存对齐,改小必须使用#param pack(1)
std::alignment_of 补足alignof的功能不仅可以返回值还提供操作
std::aligned_storage 使用其可以用来创建对应内存对齐类型的对象
std::aligned_storage<sizeof(MyStruct), alignof(MyStruct)>::type xx;
::new (&xx) MyStruct;
注意:在使用堆内存时,可能还是需要align_malloc,因为现在new并不能保证在超出最大默认对齐后,还能保证对齐是正确的如:
struct alignas(32) MyStruct
{
char a; // 1 byte
int b; // 4 bytes
short c; // 2 bytes
long long d; // 8 bytes
char e; // 1 byte
};
void* p = new MyStruct;
// warning C4316: 'MyStruct' : object allocated on the heap may not be aligned 32
返回当前平台默认最大对齐数
std::cout << alignof(std::max_align_t) << std::endl;
std::align是用来在一大块内存中返回一个符合对齐要求的地址
char buffer[] = "------------------------";
void * pt = buffer;
std::size_t space = sizeof(buffer) - 1;
std::align(alignof(int), sizeof(char), pt, space);
在buffer这个 alignof(int)对齐的内存中,找一个char大小的内存将地址存入pt中,并记录由pt开始的长度到space中
7.std::move,std::forward
这个函数并不是做移位操作,而是将左值转换成右值。c++11 类中除了构造、拷贝之外还有一种名为移动构造函数的 形式
格式如下
XXX(XXX&&)
当源对象所有权都交由目标对象的时候,就可以调用移动构造函数。
std::move会调用移动构造函数。
std::move 和 std::forward 仅仅进行转换的函数,std::move无条件转换为右值,而forward是把参数在有绑定右值的时候才转换, 二者在runtime时不做任何事
8.decltype,std::declval,std::result_of
decltype:关键字,返回表达式类型
std::declval:常配合decltype, 而且不通过构造函数返回引用类型
std::result_of:返回函数返回类型
struct Person
{
std::string name;
int code;
int value;
};
template<typename Ty>
class Range
{
public:
typedef typename Ty::value_type value_type;
Range(const Ty &t):_t(t)
{
}
template<typename Fn>
std::multimap<typename std::result_of<Fn(value_type)>::type, value_type> groupBy(Fn fn)
{
typedef decltype(std::declval<Fn>()(std::declval<value_type>())) key_type;
std::multimap<key_type, value_type> maps;
std::for_each(begin(_t), end(_t), [&maps,&fn](const value_type &item)
{
maps.insert(std::make_pair(fn(item), item));
});
return maps;
}
private:
Ty _t;
};
int main(int argc, const char * argv[])
{
std::vector<Person> pers = {{"aa",10,23},{"bb",13,24},{"aa",10,25},{"bb",13,25}};
Range< std::vector<Person> > ranges(pers);
auto a1 = ranges.groupBy([](const Person &person)
{
return person.code;
});
auto a2 = ranges.groupBy([](const Person &person)
{
return person.name;
});
PrintMap(a1,a2);
return 0;
}
template<typename T1, typename T2>
auto sum(T1 t1, T2 t2)->decltype(t1 + t2)
{
return t1 + t2;
}
9.std::remove_reference
若为引用或右值类型则取出其左值类型 ,若为值类型,则返回值类型
template<class T1, class T2>
void print_is_same() {
std::cout << std::is_same<T1, T2>() << '\n';
}
int main() {
std::cout << std::boolalpha;
print_is_same<int, int>(); // true
print_is_same<int, int &>(); // false
print_is_same<int, int &&>(); // false
print_is_same<int, std::remove_reference<int>::type>(); // true
print_is_same<int, std::remove_reference<int &>::type>(); // true
print_is_same<int, std::remove_reference<int &&>::type>(); // true
}
10.constexpr
a.用constexpr
修饰函数将限制函数的行为。首先,该函数的回返值类型不能为void。第二,函数的内容必须依照"returnexpr"的形式。第三,在参数替换后,expr
必须是个常数表示式。这些常数表示式只能够调用其他被定义为constexpr
的函数,或是其他常数表示式的数据参数。最后,有着这样修饰符的函数直到在该编译单元内被定义之前是不能够被调用的
b.constexpr解除了除了变量必须是整型或枚举类型的限制,constexpr double test = 10.0;
c.为了让用户自定义类型(user-defined type)参与构造常量表示式,构造函数也可以用constexpr
来声明
11.override,final,nullptr
override子类重载函数,final申明类不可被继承 class Test final{};,nullptr 空指针
12.强类型枚举
enum class myEnumeration
{
Val1,
Val2,
Val3 = 100,
Val4 /* = 101 */,
};
不能与int相互转换了
enum class Enum2 : unsigned int {Val1, Val2};
也可以定义成别的类
13.std::initializer_list
允许数组初始化列表
void FunctionName(std::initializer_list<float> list);
FunctionName({1.0f, -3.45f, -0.4f});
14.std::addressof
返回变量/引用等变量的物理地址
15.读取文本文件全部内容
//function 1.
std::ifstream file(path,ios::in);
std::string str((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
//function 2.
std::ifstream file(path,ios::in);
std::stringstream ss;
ss << file.rdbuf();
std::string contents(ss.str());
15.多线程
http://www.cnblogs.com/haippy/p/3284540.html