Commit 8444e5 initial commit

18 files Merged and Committed by Stefan Bühler Stefan Bühler 4 years ago
initial commit

    
1 @@ -0,0 +1,1 @@
2 + *-build
 1 @@ -0,0 +1,54 @@
 2 + cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
 3 + project(c++-benchmarks CXX)
 4 + 
 5 + include(CMakeDetermineCXXCompiler)
 6 + 
 7 + # default to Release
 8 + if("${CMAKE_BUILD_TYPE}" STREQUAL "")
 9 + »       set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE)
10 + endif("${CMAKE_BUILD_TYPE}" STREQUAL "")
11 + 
12 + 
13 + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
14 + »       set(EXTRA_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wno-unused-parameter -pedantic" CACHE STRING "Extra flags used by the compiler during all build types.")
15 + else("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
16 + »       set(EXTRA_CXX_FLAGS "" CACHE STRING "Extra flags used by the compiler during all build types.")
17 + endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
18 + 
19 + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXX_FLAGS}")
20 + 
21 + add_executable(benchmark-atomic-costs
22 + »       benchmark-atomic-costs.cpp)
23 + 
24 + add_executable(benchmark-atomic-costs-pthread
25 + »       benchmark-atomic-costs.cpp)
26 + set_target_properties(benchmark-atomic-costs-pthread
27 + »       PROPERTIES
28 + »       »       COMPILE_FLAGS "-pthread"
29 + »       »       LINK_FLAGS "-pthread")
30 + 
31 + add_executable(benchmark-shared-unique
32 + »       benchmark-shared-unique.cpp
33 + »       benchmark-shared-unique-impl.cpp)
34 + 
35 + add_executable(test-NULL-type
36 + »       test-NULL-type.cpp)
37 + 
38 + add_executable(test-base-constr
39 + »       test-base-constr.cpp)
40 + 
41 + add_executable(test-const-ref-results
42 + »       test-const-ref-results.cpp)
43 + 
44 + add_executable(test-constructor-throw
45 + »       test-constructor-throw.cpp)
46 + 
47 + add_executable(test-copy-shared-ptr
48 + »       test-copy-shared-ptr.cpp
49 + »       test-copy-shared-ptr-impl.cpp)
50 + 
51 + add_executable(test-rvalue-ref
52 + »       test-rvalue-ref.cpp)
53 + 
54 + add_executable(test-smart-factory
55 + »       test-smart-factory.cpp)
  1 @@ -0,0 +1,102 @@
  2 + 
  3 + #include "measure_time.h"
  4 + 
  5 + #include <atomic>
  6 + #include <cstdint>
  7 + #include <thread>
  8 + #include <ext/concurrence.h>
  9 + 
 10 + #define COUNT (1u << 24)
 11 + 
 12 + // use "incl" for 32-bit and "incq" for 64-bit in asm below:
 13 + // use 32-bit for now: _Atomic_word should be 32-bit too;
 14 + // 64-bit is basically as fast as 32-bit if it fits in your cache
 15 + typedef std::uint32_t counting;
 16 + 
 17 + volatile counting __attribute__ ((aligned (64))) volatile_counter;
 18 + counting __attribute__ ((aligned (64))) simple_counter;
 19 + std::atomic<counting> __attribute__ ((aligned (64))) atomic_counter;
 20 + 
 21 + _Atomic_word __attribute__ ((aligned (64))) gxx_counter;
 22 + 
 23 + void benchmark_volatile() {
 24 + »       // should be the same as asm below
 25 + »       volatile_counter = 0;
 26 + »       for (size_t i = 0; i < COUNT; ++i) {
 27 + »       »       ++volatile_counter;
 28 + »       }
 29 + }
 30 + 
 31 + void benchmark_asm() {
 32 + »       simple_counter = 0;
 33 + »       for (size_t i = 0; i < COUNT; ++i) {
 34 + »       »       asm volatile(
 35 + »       »       »       "incl %0;"
 36 + »       »       »       : "+m"(simple_counter)
 37 + »       »       );
 38 + »       }
 39 + }
 40 + 
 41 + void benchmark_local_atomic() {
 42 + »       // compiler doesn't realize no one else can read this counter and
 43 + »       // uses real atomic (i.e. "lock")
 44 + »       std::atomic<counting> local_atomic_counter;
 45 + »       local_atomic_counter = 0;
 46 + »       for (size_t i = 0; i < COUNT; ++i) {
 47 + »       »       ++local_atomic_counter;
 48 + »       }
 49 + }
 50 + 
 51 + void benchmark_atomic() {
 52 + »       // should be the same as "lock_asm"
 53 + »       atomic_counter = 0;
 54 + »       for (size_t i = 0; i < COUNT; ++i) {
 55 + »       »       ++atomic_counter;
 56 + »       }
 57 + }
 58 + 
 59 + void benchmark_lock_asm() {
 60 + »       simple_counter = 0;
 61 + »       for (size_t i = 0; i < COUNT; ++i) {
 62 + »       »       asm volatile(
 63 + »       »       »       "lock incl %0;"
 64 + »       »       »       : "+m"(simple_counter)
 65 + »       »       );
 66 + »       }
 67 + }
 68 + 
 69 + void benchmark_gxx_atomic() {
 70 + »       // if linked with pthread this will use "lock" same as atomic, otherwise
 71 + »       // it uses a simple non-volatile non-atomic add instruction
 72 + »       // https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_concurrency.html
 73 + »       // claims __atomic_add_dispatch uses a volatile counter, but this isn't
 74 + »       // true in gcc 4.9
 75 + »       gxx_counter = 0;
 76 + »       for (size_t i = 0; i < COUNT; ++i) {
 77 + »       »       __gnu_cxx::__atomic_add_dispatch(&gxx_counter, 1);
 78 + »       }
 79 + }
 80 + 
 81 + 
 82 + int main() {
 83 + //»       std::thread fake([] { return; });
 84 + //»       fake.join();
 85 + 
 86 + »       std::cout << "volatile counter    : ";
 87 + »       measure_time_with_dry_run(benchmark_volatile);
 88 + 
 89 + »       std::cout << "asm counter         : ";
 90 + »       measure_time_with_dry_run(benchmark_asm);
 91 + 
 92 + »       std::cout << "local atomic counter: ";
 93 + »       measure_time_with_dry_run(benchmark_local_atomic);
 94 + 
 95 + »       std::cout << "atomic counter      : ";
 96 + »       measure_time_with_dry_run(benchmark_atomic);
 97 + 
 98 + »       std::cout << "lock asm counter    : ";
 99 + »       measure_time_with_dry_run(benchmark_lock_asm);
100 + 
101 + »       std::cout << "gxx atomic counter  : ";
102 + »       measure_time_with_dry_run(benchmark_gxx_atomic);
103 + }
 1 @@ -0,0 +1,23 @@
 2 + 
 3 + #include "benchmark-shared-unique.h"
 4 + 
 5 + void* forward_raw(void* p) {
 6 + »       return p;
 7 + }
 8 + 
 9 + 
10 + std::unique_ptr<size_t> forward_unique(std::unique_ptr<size_t>&& p) {
11 + »       return std::move(p);
12 + }
13 + 
14 + std::shared_ptr<size_t> forward_shared(std::shared_ptr<size_t>&& p) {
15 + »       return std::move(p);
16 + }
17 + 
18 + std::unique_ptr<Large> forward_unique_large(std::unique_ptr<Large>&& p) {
19 + »       return std::move(p);
20 + }
21 + 
22 + std::shared_ptr<Large> forward_shared_large(std::shared_ptr<Large>&& p) {
23 + »       return std::move(p);
24 + }
  1 @@ -0,0 +1,128 @@
  2 + 
  3 + #include "benchmark-shared-unique.h"
  4 + 
  5 + #include "measure_time.h"
  6 + #include "make_unique.h"
  7 + 
  8 + 
  9 + #define COUNT (1u << 26)
 10 + 
 11 + void benchmark_forward_empty_raw() {
 12 + »       for (size_t i = 0; i < COUNT; ++i) {
 13 + »       »       (void) forward_raw(nullptr);
 14 + »       }
 15 + }
 16 + 
 17 + void benchmark_forward_empty_unique() {
 18 + »       for (size_t i = 0; i < COUNT; ++i) {
 19 + »       »       (void) forward_unique({});
 20 + »       }
 21 + }
 22 + 
 23 + void benchmark_forward_empty_shared() {
 24 + »       for (size_t i = 0; i < COUNT; ++i) {
 25 + »       »       (void) forward_shared({});
 26 + »       }
 27 + }
 28 + 
 29 + void benchmark_forward_empty_shared_from_unique() {
 30 + »       for (size_t i = 0; i < COUNT; ++i) {
 31 + »       »       (void) forward_shared(std::unique_ptr<size_t>{});
 32 + »       }
 33 + }
 34 + 
 35 + 
 36 + void benchmark_forward_new_raw() {
 37 + »       for (size_t i = 0; i < COUNT; ++i) {
 38 + »       »       size_t* p = new size_t{i};
 39 + »       »       (void) forward_raw(p);
 40 + »       »       delete p;
 41 + »       }
 42 + }
 43 + 
 44 + void benchmark_forward_new_unique() {
 45 + »       for (size_t i = 0; i < COUNT; ++i) {
 46 + »       »       (void) forward_unique(std::make_unique<size_t>(i));
 47 + »       }
 48 + }
 49 + 
 50 + void benchmark_forward_new_shared() {
 51 + »       for (size_t i = 0; i < COUNT; ++i) {
 52 + »       »       (void) forward_shared(std::make_shared<size_t>(i));
 53 + »       }
 54 + }
 55 + 
 56 + void benchmark_forward_new_shared_from_unique() {
 57 + »       for (size_t i = 0; i < COUNT; ++i) {
 58 + »       »       (void) forward_shared(std::make_unique<size_t>(i));
 59 + »       }
 60 + }
 61 + 
 62 + 
 63 + void benchmark_forward_new_raw_large() {
 64 + »       for (size_t i = 0; i < COUNT; ++i) {
 65 + »       »       Large* p = new Large{i};
 66 + »       »       (void) forward_raw(p);
 67 + »       »       delete p;
 68 + »       }
 69 + }
 70 + 
 71 + void benchmark_forward_new_unique_large() {
 72 + »       for (size_t i = 0; i < COUNT; ++i) {
 73 + »       »       (void) forward_unique_large(std::make_unique<Large>(i));
 74 + »       }
 75 + }
 76 + 
 77 + void benchmark_forward_new_shared_large() {
 78 + »       for (size_t i = 0; i < COUNT; ++i) {
 79 + »       »       (void) forward_shared_large(std::make_shared<Large>(i));
 80 + »       }
 81 + }
 82 + 
 83 + void benchmark_forward_new_shared_large_from_unique() {
 84 + »       for (size_t i = 0; i < COUNT; ++i) {
 85 + »       »       (void) forward_shared_large(std::make_unique<Large>(i));
 86 + »       }
 87 + }
 88 + 
 89 + int main() {
 90 + »       std::cout << "forward empty raw                   : ";
 91 + »       measure_time(benchmark_forward_empty_raw);
 92 + 
 93 + »       std::cout << "forward empty unique                : ";
 94 + »       measure_time(benchmark_forward_empty_unique);
 95 + 
 96 + »       std::cout << "forward empty shared                : ";
 97 + »       measure_time(benchmark_forward_empty_shared);
 98 + 
 99 + »       std::cout << "forward empty shared from unique    : ";
100 + »       measure_time(benchmark_forward_empty_shared_from_unique);
101 + 
102 + »       std::cout << "\n";
103 + 
104 + »       std::cout << "forward new raw                     : ";
105 + »       measure_time(benchmark_forward_new_raw);
106 + 
107 + »       std::cout << "forward new unique                  : ";
108 + »       measure_time(benchmark_forward_new_unique);
109 + 
110 + »       std::cout << "forward new shared                  : ";
111 + »       measure_time(benchmark_forward_new_shared);
112 + 
113 + »       std::cout << "forward new shared from unique      : ";
114 + »       measure_time(benchmark_forward_new_shared_from_unique);
115 + 
116 + »       std::cout << "\n";
117 + 
118 + »       std::cout << "forward new raw large               : ";
119 + »       measure_time(benchmark_forward_new_raw_large);
120 + 
121 + »       std::cout << "forward new unique large            : ";
122 + »       measure_time(benchmark_forward_new_unique_large);
123 + 
124 + »       std::cout << "forward new shared large            : ";
125 + »       measure_time(benchmark_forward_new_shared_large);
126 + 
127 + »       std::cout << "forward new shared large from unique: ";
128 + »       measure_time(benchmark_forward_new_shared_large_from_unique);
129 + }
 1 @@ -0,0 +1,16 @@
 2 + #include <memory>
 3 + 
 4 + struct Large {
 5 + »       size_t x;
 6 + »       char filler[512 - sizeof(size_t)] = {};
 7 + 
 8 + »       Large(size_t x) : x(x) {}
 9 + };
10 + 
11 + void* forward_raw(void* p);
12 + 
13 + std::unique_ptr<size_t> forward_unique(std::unique_ptr<size_t>&& p);
14 + std::shared_ptr<size_t> forward_shared(std::shared_ptr<size_t>&& p);
15 + 
16 + std::unique_ptr<Large> forward_unique_large(std::unique_ptr<Large>&& p);
17 + std::shared_ptr<Large> forward_shared_large(std::shared_ptr<Large>&& p);
 1 @@ -0,0 +1,36 @@
 2 + #pragma once
 3 + 
 4 + #include <memory>
 5 + 
 6 + #if __cplusplus <= 201103L
 7 + 
 8 + namespace {
 9 +   template<class T>
10 +   struct is_unbound_array : std::false_type {};
11 + 
12 +   template<class T>
13 +   struct is_unbound_array<T[]> : std::true_type {};
14 + 
15 +   template<class T>
16 +   struct is_bound_array : std::false_type {};
17 + 
18 +   template<class T, std::size_t N>
19 +   struct is_bound_array<T[N]> : std::true_type {};
20 + }
21 + 
22 + namespace std {
23 +   template<typename T, typename... Args>
24 +   typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type make_unique(Args&&... args) {
25 +       return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
26 +   }
27 + 
28 +   template<typename T>
29 +   typename std::enable_if<is_unbound_array<T>::value, std::unique_ptr<T>>::type make_unique(size_t size) {
30 +       return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
31 +   }
32 + 
33 +   template< class T, class... Args >
34 +   typename std::enable_if<is_bound_array<T>::value>::type make_unique( Args&&... args ) = delete;
35 + }
36 + 
37 + #endif
 1 @@ -0,0 +1,20 @@
 2 + #pragma once
 3 + 
 4 + #include <chrono>
 5 + #include <iostream>
 6 + 
 7 + template<typename Callable>
 8 + void measure_time(Callable&& callable) {
 9 + »       using namespace std::chrono;
10 + »       steady_clock::time_point t_start = steady_clock::now();
11 + »       callable();
12 + »       duration<double> time_span = duration_cast<duration<double>>(steady_clock::now() - t_start);
13 + 
14 + »       std::cout << "took " << time_span.count() << " seconds\n";
15 + }
16 + 
17 + template<typename Callable>
18 + void measure_time_with_dry_run(Callable&& callable) {
19 + »       callable();
20 + »       measure_time(std::forward<Callable>(callable));
21 + }
 1 @@ -0,0 +1,15 @@
 2 + 
 3 + #include "type_name.h"
 4 + 
 5 + #include <memory>
 6 + #include <utility>
 7 + #include <iostream>
 8 + 
 9 + int main() {
10 + »       auto o = NULL;
11 + »       int* n(reinterpret_cast<int*>(o));
12 + »       // auto n = std::make_pair(0, (intptr_t) NULL);
13 + »       std::cout << "decltype(n) is " << TYPE_NAME(n) << '\n';
14 + »       auto p = std::make_pair(std::ref(o), nullptr);
15 + »       std::cout << "decltype(p) is " << TYPE_NAME(p) << '\n';
16 + }
 1 @@ -0,0 +1,30 @@
 2 + 
 3 + #include <iostream>
 4 + 
 5 + #define L(s) std::cerr << s << "\n"
 6 + 
 7 + struct A {
 8 + »       A() { L("A::A()"); }
 9 + »       A(A&&) { L("A::A(A&&)"); }
10 + »       A(const A&) { L("A::A(const A&)"); }
11 + »       ~A() { L("A::~A()"); }
12 + };
13 + 
14 + struct B: A {
15 + »       B() { L("B::B()"); }
16 + »       B(A&&) { L("B::B(A&&)"); }
17 + »       //B(B&&) { L("B::B(B&&)"); }
18 + »       B(const A&) { L("B::B(const A&)"); }
19 + »       // B(const B&) { L("B::B(const B&)"); }
20 + »       ~B() { L("B::~B()"); }
21 + };
22 + 
23 + int main() {
24 + »       L("A a1;");
25 + »       A a1;
26 + »       L("B b1(a1);");
27 + »       B b1(a1);
28 + »       L("B b1(b1);");
29 + »       B b2(static_cast<A&>(b1));
30 + »       return 0;
31 + }
 1 @@ -0,0 +1,22 @@
 2 + #include <algorithm>
 3 + #include <memory>
 4 + #include <iostream>
 5 + 
 6 + class C {
 7 + public:
 8 + »       int valid;
 9 + »       C() : valid(1) { }
10 + »       ~C() { valid = 0; }
11 + };
12 + 
13 + /* some "random" comparison, doesn't matter */
14 + bool operator<(C const& a, C const& b) {
15 + »       return reinterpret_cast<uintptr_t>(&a) < reinterpret_cast<uintptr_t>(&b);
16 + }
17 + 
18 + int main() {
19 + »       auto const& m =
20 + »       »       // std::max(*std::make_shared<C>(), *std::make_shared<C>());
21 + »       »       std::max(C(), C());
22 + »       std::cout << m.valid << "\n";
23 + }
 1 @@ -0,0 +1,35 @@
 2 + 
 3 + #include <exception>
 4 + #include <memory>
 5 + #include <type_traits>
 6 + 
 7 + #include "make_unique.h"
 8 + 
 9 + struct C {
10 + private:
11 +   struct private_type { };
12 +   C(private_type) { }
13 +   int *m_i = nullptr;
14 + 
15 + public:
16 +   C() : C(private_type()) { m_i = new int; throw std::exception(); }
17 +   ~C() { delete m_i; }
18 +   C(C const&) = delete;
19 +   C& operator=(C const&) = delete;
20 + };
21 + 
22 + 
23 + struct D {
24 + »       std::unique_ptr<int> m_i;
25 + »       D() : m_i(std::make_unique<int>()) { m_i = std::make_unique<int>(); throw std::exception(); }
26 + };
27 + 
28 + int main() {
29 + »       try {
30 + »       »       C c;
31 + »       } catch (...) { }
32 + 
33 + »       auto a = std::make_unique<int[]>(10);
34 + 
35 + »       return 0;
36 + }
 1 @@ -0,0 +1,10 @@
 2 + 
 3 + #include <memory>
 4 + 
 5 + void copy_ptr(std::shared_ptr<int>& a, std::shared_ptr<int> const& b) {
 6 + »       a = b;
 7 + }
 8 + 
 9 + void move_ptr(std::shared_ptr<int>& a, std::shared_ptr<int>& b) {
10 + »       a = std::move(b);
11 + }
1 @@ -0,0 +1,8 @@
2 + 
3 + #include <memory>
4 + 
5 + void copy_ptr(std::shared_ptr<int>& a, std::shared_ptr<int> const& b);
6 + void move_ptr(std::shared_ptr<int>& a, std::shared_ptr<int>& b);
7 + 
8 + int main() {
9 + }
 1 @@ -0,0 +1,23 @@
 2 + 
 3 + #include "type_name.h"
 4 + 
 5 + #include <iostream>
 6 + 
 7 + void f(const int&) {
 8 + }
 9 + 
10 + #define T(v) std::cout << #v << ": " << TYPE_NAME(v) << "\n"
11 + 
12 + int main() {
13 + »       auto&& i = 1;
14 + »       auto& ri = i;
15 + »       auto const& x = std::move(ri);
16 + »       decltype(ri) y = ri;
17 + »       f(i);
18 + //»       f(std::forward(i));
19 + »       T(i);
20 + »       T(ri);
21 + »       T(x);
22 + »       T(y);
23 + »       return 0;
24 + }
  1 @@ -0,0 +1,118 @@
  2 + 
  3 + #include <memory>
  4 + #include <type_traits>
  5 + 
  6 + class C {
  7 + protected:
  8 +   struct Protected {
  9 +   private:
 10 +     Protected() {};
 11 +   public:
 12 +     static Protected make() { return { }; }
 13 +   };
 14 +   int m_x;
 15 + 
 16 + private:
 17 +   struct Private {
 18 +   private:
 19 +     Private() {};
 20 +   public:
 21 +     static Private make() { return { }; }
 22 +   };
 23 +   int m_y;
 24 + 
 25 + public:
 26 +   /* private constructor: */
 27 +   C(Private, int x, int y) : m_x(x), m_y(y) { }
 28 +   /* protected constructor: */
 29 +   C(Protected, int x) : C(Private::make(), x, 2*x) { }
 30 + 
 31 +   void leak_private_type(Private) { }
 32 + 
 33 +   static std::unique_ptr<C> Create(int x) {
 34 +     return std::unique_ptr<C>(new C(Private::make(), x, 2*x));
 35 +   }
 36 + };
 37 + 
 38 + class D : public C {
 39 + private:
 40 +   struct Private { };
 41 + public:
 42 +   D(Private&, int x) : C(Protected::make(), x) { }
 43 + 
 44 +   static std::shared_ptr<D> Create(int x) {
 45 +     Private p;
 46 +     return std::make_shared<D>(p, 4*x);
 47 +   }
 48 + };
 49 + 
 50 + 
 51 + class A {
 52 +    struct this_is_private {
 53 +    };
 54 + 
 55 +  public:
 56 +    explicit A(const this_is_private &, int) {}
 57 + 
 58 +    static ::std::shared_ptr<A> create(int x) {
 59 +       return ::std::make_shared<A>(this_is_private{}, x);
 60 +    }
 61 + 
 62 +  protected:
 63 +    A(const A &) = delete;
 64 +    const A &operator =(const A &) = delete;
 65 + };
 66 + 
 67 + ::std::shared_ptr<A> foo(int x)
 68 + {
 69 +    return A::create(x);
 70 + }
 71 + 
 72 + 
 73 +   /* usage: decltype(return_args(&Class::memberfunction)) */
 74 +   template<typename Base, typename Result, typename... Args>
 75 +   std::tuple<Args...> return_args(Result (Base::*func)(Args...));
 76 + 
 77 +   /* usage: decltype(result_of(&Class::memberfunction)) */
 78 +   template<typename Base, typename Result, typename... Args>
 79 +   Result result_of(Result (Base::*func)(Args...));
 80 + 
 81 +   /* usage: decay_tuple_element<0, decltype(return_args(&Class::memberfunction))> */
 82 +   template <size_t i, typename Tuple>
 83 +   using decay_tuple_element = typename std::decay<typename std::tuple_element<i, Tuple>::type>::type;
 84 + 
 85 + 
 86 +   struct _is_static_castable_impl
 87 +   {
 88 +     template<typename _From, typename _To, typename = decltype(static_cast<_To>(std::declval<_From>()))>
 89 +     static std::true_type __test(int);
 90 + 
 91 +     template<typename, typename>
 92 +     static std::false_type __test(...);
 93 +   };
 94 + 
 95 +   template<typename _From, typename _To>
 96 +   struct is_static_castable
 97 +   : public _is_static_castable_impl
 98 +   {
 99 +     typedef decltype(__test<_From, _To>(0)) type;
100 +   };
101 + 
102 +   template<typename _From, typename _To>
103 +   using is_static_castable_t = typename is_static_castable<_From, _To>::type;
104 + 
105 + 
106 + 
107 + int main() {
108 +   auto c = C::Create(0);
109 +   auto d = D::Create(0);
110 + 
111 +   typedef decay_tuple_element<0, decltype(return_args(&C::leak_private_type))> Private;
112 +   Private::make();
113 + 
114 + 
115 +   auto a1 = foo(0);
116 +   auto a2 = std::shared_ptr<A>(new A({}, 0));
117 + 
118 + //  C c1({}, 0, 0);
119 + }
 1 @@ -0,0 +1,38 @@
 2 + #pragma once
 3 + 
 4 + #include <type_traits>
 5 + #include <typeinfo>
 6 + #ifndef _MSC_VER
 7 + # include <cxxabi.h>
 8 + #endif
 9 + #include <memory>
10 + #include <string>
11 + #include <cstdlib>
12 + 
13 + template <class T>
14 + std::string
15 + type_name()
16 + {
17 + »       typedef typename std::remove_reference<T>::type TR;
18 + »       std::unique_ptr<char, void(*)(void*)> own
19 + »       »       (
20 + #ifndef _MSC_VER
21 + »       »       »       abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr),
22 + #else
23 + »       »       »       nullptr,
24 + #endif
25 + »       »       »       std::free
26 + »       »       );
27 + »       std::string r = own != nullptr ? own.get() : typeid(TR).name();
28 + »       if (std::is_const<TR>::value)
29 + »       »       r += " const";
30 + »       if (std::is_volatile<TR>::value)
31 + »       »       r += " volatile";
32 + »       if (std::is_lvalue_reference<T>::value)
33 + »       »       r += "&";
34 + »       else if (std::is_rvalue_reference<T>::value)
35 + »       »       r += "&&";
36 + »       return r;
37 + }
38 + 
39 + #define TYPE_NAME(p) (type_name<decltype(p)>())