Article directory
2. C++ default arguments
21. Template Template Parameters
Template parameter: is a template type
// Type your code here, or load an example.
#include <string>
#include <iostream>
template<typename T>
struct X{
};
template<typename Z, template<typename T> typename C>
struct Y{
C<Z> c;
};
template<class T>
struct X2{
T t;
};
template<template<typename T, typename T2, typename T3> typename S>
struct Str{
S<char, std::char_traits<char>, std::allocator<char>> str;
};
int main()
{
Y<int, X2> y{
};
y.c.t=100;
std::cout<<y.c.t<<'\n';
//使用std::string error,因为别名的话,与Str类模板的参数不匹配,可以调试看看
Str<std::basic_string> s;
s.str="abc";
std::cout<<s.str<<'\n';
}
22. C++11 formal parameter pack
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
// link:https://en.cppreference.com/w/cpp/language/parameter_pack
// type ... pack-name (optional) (1)
template<size_t...args>
struct X{
void f(){
// pattern ... (6)
for(const auto& i: {
args...})
{
std::cout<<i<<' ';
std::cout<<'\n';
}
}
};
// typename|class ... pack-name (optional) (2)
// pack-name ... pack-param-name (optional) (5)
template<typename...Args>
void f(Args...args)
{
((std::cout<<args<<' '),...);//折叠表达式
}
// type-constraint ... pack-name (optional) (3) (since C++20)
// template<std::integral ...Args>
// void f2(Args...args)
// {
// ((std::cout<<args<<' '),...);
// }
// template < parameter-list > typename|class ... pack-name (optional) (4) (since C++17)
template<typename T1, typename T2>
struct T{
};
template<template<typename T1, typename T2>typename...Args>
struct Y{
};
// pattern ... (6) 递归展开
void print(){
}
template<typename T, typename ...Args>
void print(T t, Args...args)
{
std::cout<<t<<' ';
print(args...);
}
template<size_t...Args>
void t()
{
int array[sizeof...(Args)]{
Args...};
for(auto const& i: array)
{
std::cout<<i<<' ';
}
endl(std::cout);
}
int main()
{
X<1,2,3> x;
x.f();
f(4,5,6,"wangji");
// f2(7);
Y<std::basic_string,T,T>y;
endl(std::cout);
print('a','b');
t<1,2>();
}
24.std::nothrow
When using new to apply for a block of memory fails, throwing an exception std::bad_alloc is a standard behavior stipulated in the C++ standard, so use try { p = new int[size];} catch(std::bad_alloc) { ... } processing Way.
The difference between std::nothrow and standard new is that new will throw an exception when it fails to allocate memory, while "new(std::nothrow)" will return a null pointer when it fails to allocate memory.
After the new operator fails to allocate memory, the default behavior is not to return NULL, but to throw an exception std::bad_alloc. So it doesn't make sense to judge whether the return value is NULL
#include <iostream>
#include <new> // std::nothrow
// reference: http://www.cplusplus.com/reference/new/nothrow/
int test_nothrow1()
{
std::cout << "Attempting to allocate 1 MiB...";
char* p = new (std::nothrow) char[1048576];
if (p == 0)
std::cout << "Failed!\n";
else {
std::cout << "Succeeded!\n";
delete[] p;
}
return 0;
}
// reference: http://en.cppreference.com/w/cpp/memory/new/nothrow
int test_nothrow2()
{
try {
while (true) {
new int[100000000ul]; // throwing overload
}
}
catch (const std::bad_alloc& e) {
std::cout << e.what() << '\n';
}
while (true) {
int* p = new(std::nothrow) int[100000000ul]; // non-throwing overload
if (p == nullptr) {
std::cout << "Allocation returned nullptr\n";
break;
}
}
return 0;
}
25.std::call_once与pthread_once
pthread_once can implement a multi-threaded singleton, and can register the exit function of the singleton object in the function;
- ref:muduo:Singleton.h
- has_no_destroy
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#ifndef MUDUO_BASE_SINGLETON_H
#define MUDUO_BASE_SINGLETON_H
#include <assert.h>
#include <pthread.h>
#include <stdlib.h> // atexit
#include "muduo/base/noncopyable.h"
namespace muduo {
namespace detail {
// This doesn't detect inherited member functions!
// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
template <typename T>
struct has_no_destroy {
template <typename C>
static char test(decltype(&C::no_destroy));
template <typename C>
static int32_t test(...);
const static bool value = sizeof(test<T>(0)) == 1;
};
} // namespace detail
template <typename T>
class Singleton : noncopyable {
public:
Singleton() = delete;
~Singleton() = delete;
static T& instance() {
pthread_once(&ponce_, &Singleton::init);
assert(value_ != NULL);
return *value_;
}
private:
static void init() {
value_ = new T();
if (!detail::has_no_destroy<T>::value) {
::atexit(destroy);
}
}
static void destroy() {
typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
T_must_be_complete_type dummy;
(void)dummy;
delete value_;
value_ = NULL;
}
private:
static pthread_once_t ponce_;
static T* value_;
};
template <typename T>
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;
template <typename T>
T* Singleton<T>::value_ = NULL;
} // namespace muduo
#endif // MUDUO_BASE_SINGLETON_H
The function of std::call_once is similar to pthread_once, but the destruction of the singleton object has to use atexit
- The first parameter of the std::call_once function is an object of std::once_flag, and the second parameter can be a function, a member function, a function object, or a lambda function.
template< class Function, class... Args >
void call_once ( std::once_flag& flag, Function&& f, Args&& args... );
参数解析:
flag - an object, for which exactly one function gets executed
f - 需要被调用的函数
args... - 传递给函数f的参数(可以多个)
返回值为 (none)
抛出异常
std::system_error if any condition prevents calls to call_once from executing as specified any exception thrown by f
#include <iostream>
#include <thread>
#include <mutex>
std::once_flag flag1;
void simple_do_once()
{
std::call_once(flag1, [](){
std::cout << "Simple example: called once\n"; });
}
int main()
{
std::thread st1(simple_do_once);
std::thread st2(simple_do_once);
std::thread st3(simple_do_once);
std::thread st4(simple_do_once);
st1.join();
st2.join();
st3.join();
st4.join();
}
reference: