initial commit
This commit is contained in:
commit
8444e5ce55
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*-build
|
54
CMakeLists.txt
Normal file
54
CMakeLists.txt
Normal file
@ -0,0 +1,54 @@
|
||||
cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
|
||||
project(c++-benchmarks CXX)
|
||||
|
||||
include(CMakeDetermineCXXCompiler)
|
||||
|
||||
# default to Release
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
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)
|
||||
endif("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
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.")
|
||||
else("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(EXTRA_CXX_FLAGS "" CACHE STRING "Extra flags used by the compiler during all build types.")
|
||||
endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXX_FLAGS}")
|
||||
|
||||
add_executable(benchmark-atomic-costs
|
||||
benchmark-atomic-costs.cpp)
|
||||
|
||||
add_executable(benchmark-atomic-costs-pthread
|
||||
benchmark-atomic-costs.cpp)
|
||||
set_target_properties(benchmark-atomic-costs-pthread
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-pthread"
|
||||
LINK_FLAGS "-pthread")
|
||||
|
||||
add_executable(benchmark-shared-unique
|
||||
benchmark-shared-unique.cpp
|
||||
benchmark-shared-unique-impl.cpp)
|
||||
|
||||
add_executable(test-NULL-type
|
||||
test-NULL-type.cpp)
|
||||
|
||||
add_executable(test-base-constr
|
||||
test-base-constr.cpp)
|
||||
|
||||
add_executable(test-const-ref-results
|
||||
test-const-ref-results.cpp)
|
||||
|
||||
add_executable(test-constructor-throw
|
||||
test-constructor-throw.cpp)
|
||||
|
||||
add_executable(test-copy-shared-ptr
|
||||
test-copy-shared-ptr.cpp
|
||||
test-copy-shared-ptr-impl.cpp)
|
||||
|
||||
add_executable(test-rvalue-ref
|
||||
test-rvalue-ref.cpp)
|
||||
|
||||
add_executable(test-smart-factory
|
||||
test-smart-factory.cpp)
|
102
benchmark-atomic-costs.cpp
Normal file
102
benchmark-atomic-costs.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
|
||||
#include "measure_time.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
#include <ext/concurrence.h>
|
||||
|
||||
#define COUNT (1u << 24)
|
||||
|
||||
// use "incl" for 32-bit and "incq" for 64-bit in asm below:
|
||||
// use 32-bit for now: _Atomic_word should be 32-bit too;
|
||||
// 64-bit is basically as fast as 32-bit if it fits in your cache
|
||||
typedef std::uint32_t counting;
|
||||
|
||||
volatile counting __attribute__ ((aligned (64))) volatile_counter;
|
||||
counting __attribute__ ((aligned (64))) simple_counter;
|
||||
std::atomic<counting> __attribute__ ((aligned (64))) atomic_counter;
|
||||
|
||||
_Atomic_word __attribute__ ((aligned (64))) gxx_counter;
|
||||
|
||||
void benchmark_volatile() {
|
||||
// should be the same as asm below
|
||||
volatile_counter = 0;
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
++volatile_counter;
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_asm() {
|
||||
simple_counter = 0;
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
asm volatile(
|
||||
"incl %0;"
|
||||
: "+m"(simple_counter)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_local_atomic() {
|
||||
// compiler doesn't realize no one else can read this counter and
|
||||
// uses real atomic (i.e. "lock")
|
||||
std::atomic<counting> local_atomic_counter;
|
||||
local_atomic_counter = 0;
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
++local_atomic_counter;
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_atomic() {
|
||||
// should be the same as "lock_asm"
|
||||
atomic_counter = 0;
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
++atomic_counter;
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_lock_asm() {
|
||||
simple_counter = 0;
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
asm volatile(
|
||||
"lock incl %0;"
|
||||
: "+m"(simple_counter)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_gxx_atomic() {
|
||||
// if linked with pthread this will use "lock" same as atomic, otherwise
|
||||
// it uses a simple non-volatile non-atomic add instruction
|
||||
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_concurrency.html
|
||||
// claims __atomic_add_dispatch uses a volatile counter, but this isn't
|
||||
// true in gcc 4.9
|
||||
gxx_counter = 0;
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
__gnu_cxx::__atomic_add_dispatch(&gxx_counter, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
// std::thread fake([] { return; });
|
||||
// fake.join();
|
||||
|
||||
std::cout << "volatile counter : ";
|
||||
measure_time_with_dry_run(benchmark_volatile);
|
||||
|
||||
std::cout << "asm counter : ";
|
||||
measure_time_with_dry_run(benchmark_asm);
|
||||
|
||||
std::cout << "local atomic counter: ";
|
||||
measure_time_with_dry_run(benchmark_local_atomic);
|
||||
|
||||
std::cout << "atomic counter : ";
|
||||
measure_time_with_dry_run(benchmark_atomic);
|
||||
|
||||
std::cout << "lock asm counter : ";
|
||||
measure_time_with_dry_run(benchmark_lock_asm);
|
||||
|
||||
std::cout << "gxx atomic counter : ";
|
||||
measure_time_with_dry_run(benchmark_gxx_atomic);
|
||||
}
|
0
benchmark-results.txt
Normal file
0
benchmark-results.txt
Normal file
23
benchmark-shared-unique-impl.cpp
Normal file
23
benchmark-shared-unique-impl.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
#include "benchmark-shared-unique.h"
|
||||
|
||||
void* forward_raw(void* p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<size_t> forward_unique(std::unique_ptr<size_t>&& p) {
|
||||
return std::move(p);
|
||||
}
|
||||
|
||||
std::shared_ptr<size_t> forward_shared(std::shared_ptr<size_t>&& p) {
|
||||
return std::move(p);
|
||||
}
|
||||
|
||||
std::unique_ptr<Large> forward_unique_large(std::unique_ptr<Large>&& p) {
|
||||
return std::move(p);
|
||||
}
|
||||
|
||||
std::shared_ptr<Large> forward_shared_large(std::shared_ptr<Large>&& p) {
|
||||
return std::move(p);
|
||||
}
|
128
benchmark-shared-unique.cpp
Normal file
128
benchmark-shared-unique.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
|
||||
#include "benchmark-shared-unique.h"
|
||||
|
||||
#include "measure_time.h"
|
||||
#include "make_unique.h"
|
||||
|
||||
|
||||
#define COUNT (1u << 26)
|
||||
|
||||
void benchmark_forward_empty_raw() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_raw(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_forward_empty_unique() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_unique({});
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_forward_empty_shared() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_shared({});
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_forward_empty_shared_from_unique() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_shared(std::unique_ptr<size_t>{});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void benchmark_forward_new_raw() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
size_t* p = new size_t{i};
|
||||
(void) forward_raw(p);
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_forward_new_unique() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_unique(std::make_unique<size_t>(i));
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_forward_new_shared() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_shared(std::make_shared<size_t>(i));
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_forward_new_shared_from_unique() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_shared(std::make_unique<size_t>(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void benchmark_forward_new_raw_large() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
Large* p = new Large{i};
|
||||
(void) forward_raw(p);
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_forward_new_unique_large() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_unique_large(std::make_unique<Large>(i));
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_forward_new_shared_large() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_shared_large(std::make_shared<Large>(i));
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_forward_new_shared_large_from_unique() {
|
||||
for (size_t i = 0; i < COUNT; ++i) {
|
||||
(void) forward_shared_large(std::make_unique<Large>(i));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "forward empty raw : ";
|
||||
measure_time(benchmark_forward_empty_raw);
|
||||
|
||||
std::cout << "forward empty unique : ";
|
||||
measure_time(benchmark_forward_empty_unique);
|
||||
|
||||
std::cout << "forward empty shared : ";
|
||||
measure_time(benchmark_forward_empty_shared);
|
||||
|
||||
std::cout << "forward empty shared from unique : ";
|
||||
measure_time(benchmark_forward_empty_shared_from_unique);
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
std::cout << "forward new raw : ";
|
||||
measure_time(benchmark_forward_new_raw);
|
||||
|
||||
std::cout << "forward new unique : ";
|
||||
measure_time(benchmark_forward_new_unique);
|
||||
|
||||
std::cout << "forward new shared : ";
|
||||
measure_time(benchmark_forward_new_shared);
|
||||
|
||||
std::cout << "forward new shared from unique : ";
|
||||
measure_time(benchmark_forward_new_shared_from_unique);
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
std::cout << "forward new raw large : ";
|
||||
measure_time(benchmark_forward_new_raw_large);
|
||||
|
||||
std::cout << "forward new unique large : ";
|
||||
measure_time(benchmark_forward_new_unique_large);
|
||||
|
||||
std::cout << "forward new shared large : ";
|
||||
measure_time(benchmark_forward_new_shared_large);
|
||||
|
||||
std::cout << "forward new shared large from unique: ";
|
||||
measure_time(benchmark_forward_new_shared_large_from_unique);
|
||||
}
|
16
benchmark-shared-unique.h
Normal file
16
benchmark-shared-unique.h
Normal file
@ -0,0 +1,16 @@
|
||||
#include <memory>
|
||||
|
||||
struct Large {
|
||||
size_t x;
|
||||
char filler[512 - sizeof(size_t)] = {};
|
||||
|
||||
Large(size_t x) : x(x) {}
|
||||
};
|
||||
|
||||
void* forward_raw(void* p);
|
||||
|
||||
std::unique_ptr<size_t> forward_unique(std::unique_ptr<size_t>&& p);
|
||||
std::shared_ptr<size_t> forward_shared(std::shared_ptr<size_t>&& p);
|
||||
|
||||
std::unique_ptr<Large> forward_unique_large(std::unique_ptr<Large>&& p);
|
||||
std::shared_ptr<Large> forward_shared_large(std::shared_ptr<Large>&& p);
|
36
make_unique.h
Normal file
36
make_unique.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#if __cplusplus <= 201103L
|
||||
|
||||
namespace {
|
||||
template<class T>
|
||||
struct is_unbound_array : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_unbound_array<T[]> : std::true_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_bound_array : std::false_type {};
|
||||
|
||||
template<class T, std::size_t N>
|
||||
struct is_bound_array<T[N]> : std::true_type {};
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template<typename T, typename... Args>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type make_unique(Args&&... args) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<is_unbound_array<T>::value, std::unique_ptr<T>>::type make_unique(size_t size) {
|
||||
return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
|
||||
}
|
||||
|
||||
template< class T, class... Args >
|
||||
typename std::enable_if<is_bound_array<T>::value>::type make_unique( Args&&... args ) = delete;
|
||||
}
|
||||
|
||||
#endif
|
20
measure_time.h
Normal file
20
measure_time.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
template<typename Callable>
|
||||
void measure_time(Callable&& callable) {
|
||||
using namespace std::chrono;
|
||||
steady_clock::time_point t_start = steady_clock::now();
|
||||
callable();
|
||||
duration<double> time_span = duration_cast<duration<double>>(steady_clock::now() - t_start);
|
||||
|
||||
std::cout << "took " << time_span.count() << " seconds\n";
|
||||
}
|
||||
|
||||
template<typename Callable>
|
||||
void measure_time_with_dry_run(Callable&& callable) {
|
||||
callable();
|
||||
measure_time(std::forward<Callable>(callable));
|
||||
}
|
15
test-NULL-type.cpp
Normal file
15
test-NULL-type.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
#include "type_name.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
auto o = NULL;
|
||||
int* n(reinterpret_cast<int*>(o));
|
||||
// auto n = std::make_pair(0, (intptr_t) NULL);
|
||||
std::cout << "decltype(n) is " << TYPE_NAME(n) << '\n';
|
||||
auto p = std::make_pair(std::ref(o), nullptr);
|
||||
std::cout << "decltype(p) is " << TYPE_NAME(p) << '\n';
|
||||
}
|
30
test-base-constr.cpp
Normal file
30
test-base-constr.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define L(s) std::cerr << s << "\n"
|
||||
|
||||
struct A {
|
||||
A() { L("A::A()"); }
|
||||
A(A&&) { L("A::A(A&&)"); }
|
||||
A(const A&) { L("A::A(const A&)"); }
|
||||
~A() { L("A::~A()"); }
|
||||
};
|
||||
|
||||
struct B: A {
|
||||
B() { L("B::B()"); }
|
||||
B(A&&) { L("B::B(A&&)"); }
|
||||
//B(B&&) { L("B::B(B&&)"); }
|
||||
B(const A&) { L("B::B(const A&)"); }
|
||||
// B(const B&) { L("B::B(const B&)"); }
|
||||
~B() { L("B::~B()"); }
|
||||
};
|
||||
|
||||
int main() {
|
||||
L("A a1;");
|
||||
A a1;
|
||||
L("B b1(a1);");
|
||||
B b1(a1);
|
||||
L("B b1(b1);");
|
||||
B b2(static_cast<A&>(b1));
|
||||
return 0;
|
||||
}
|
22
test-const-ref-results.cpp
Normal file
22
test-const-ref-results.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
class C {
|
||||
public:
|
||||
int valid;
|
||||
C() : valid(1) { }
|
||||
~C() { valid = 0; }
|
||||
};
|
||||
|
||||
/* some "random" comparison, doesn't matter */
|
||||
bool operator<(C const& a, C const& b) {
|
||||
return reinterpret_cast<uintptr_t>(&a) < reinterpret_cast<uintptr_t>(&b);
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto const& m =
|
||||
// std::max(*std::make_shared<C>(), *std::make_shared<C>());
|
||||
std::max(C(), C());
|
||||
std::cout << m.valid << "\n";
|
||||
}
|
35
test-constructor-throw.cpp
Normal file
35
test-constructor-throw.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "make_unique.h"
|
||||
|
||||
struct C {
|
||||
private:
|
||||
struct private_type { };
|
||||
C(private_type) { }
|
||||
int *m_i = nullptr;
|
||||
|
||||
public:
|
||||
C() : C(private_type()) { m_i = new int; throw std::exception(); }
|
||||
~C() { delete m_i; }
|
||||
C(C const&) = delete;
|
||||
C& operator=(C const&) = delete;
|
||||
};
|
||||
|
||||
|
||||
struct D {
|
||||
std::unique_ptr<int> m_i;
|
||||
D() : m_i(std::make_unique<int>()) { m_i = std::make_unique<int>(); throw std::exception(); }
|
||||
};
|
||||
|
||||
int main() {
|
||||
try {
|
||||
C c;
|
||||
} catch (...) { }
|
||||
|
||||
auto a = std::make_unique<int[]>(10);
|
||||
|
||||
return 0;
|
||||
}
|
10
test-copy-shared-ptr-impl.cpp
Normal file
10
test-copy-shared-ptr-impl.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
void copy_ptr(std::shared_ptr<int>& a, std::shared_ptr<int> const& b) {
|
||||
a = b;
|
||||
}
|
||||
|
||||
void move_ptr(std::shared_ptr<int>& a, std::shared_ptr<int>& b) {
|
||||
a = std::move(b);
|
||||
}
|
8
test-copy-shared-ptr.cpp
Normal file
8
test-copy-shared-ptr.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
void copy_ptr(std::shared_ptr<int>& a, std::shared_ptr<int> const& b);
|
||||
void move_ptr(std::shared_ptr<int>& a, std::shared_ptr<int>& b);
|
||||
|
||||
int main() {
|
||||
}
|
23
test-rvalue-ref.cpp
Normal file
23
test-rvalue-ref.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
#include "type_name.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void f(const int&) {
|
||||
}
|
||||
|
||||
#define T(v) std::cout << #v << ": " << TYPE_NAME(v) << "\n"
|
||||
|
||||
int main() {
|
||||
auto&& i = 1;
|
||||
auto& ri = i;
|
||||
auto const& x = std::move(ri);
|
||||
decltype(ri) y = ri;
|
||||
f(i);
|
||||
// f(std::forward(i));
|
||||
T(i);
|
||||
T(ri);
|
||||
T(x);
|
||||
T(y);
|
||||
return 0;
|
||||
}
|
118
test-smart-factory.cpp
Normal file
118
test-smart-factory.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
class C {
|
||||
protected:
|
||||
struct Protected {
|
||||
private:
|
||||
Protected() {};
|
||||
public:
|
||||
static Protected make() { return { }; }
|
||||
};
|
||||
int m_x;
|
||||
|
||||
private:
|
||||
struct Private {
|
||||
private:
|
||||
Private() {};
|
||||
public:
|
||||
static Private make() { return { }; }
|
||||
};
|
||||
int m_y;
|
||||
|
||||
public:
|
||||
/* private constructor: */
|
||||
C(Private, int x, int y) : m_x(x), m_y(y) { }
|
||||
/* protected constructor: */
|
||||
C(Protected, int x) : C(Private::make(), x, 2*x) { }
|
||||
|
||||
void leak_private_type(Private) { }
|
||||
|
||||
static std::unique_ptr<C> Create(int x) {
|
||||
return std::unique_ptr<C>(new C(Private::make(), x, 2*x));
|
||||
}
|
||||
};
|
||||
|
||||
class D : public C {
|
||||
private:
|
||||
struct Private { };
|
||||
public:
|
||||
D(Private&, int x) : C(Protected::make(), x) { }
|
||||
|
||||
static std::shared_ptr<D> Create(int x) {
|
||||
Private p;
|
||||
return std::make_shared<D>(p, 4*x);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class A {
|
||||
struct this_is_private {
|
||||
};
|
||||
|
||||
public:
|
||||
explicit A(const this_is_private &, int) {}
|
||||
|
||||
static ::std::shared_ptr<A> create(int x) {
|
||||
return ::std::make_shared<A>(this_is_private{}, x);
|
||||
}
|
||||
|
||||
protected:
|
||||
A(const A &) = delete;
|
||||
const A &operator =(const A &) = delete;
|
||||
};
|
||||
|
||||
::std::shared_ptr<A> foo(int x)
|
||||
{
|
||||
return A::create(x);
|
||||
}
|
||||
|
||||
|
||||
/* usage: decltype(return_args(&Class::memberfunction)) */
|
||||
template<typename Base, typename Result, typename... Args>
|
||||
std::tuple<Args...> return_args(Result (Base::*func)(Args...));
|
||||
|
||||
/* usage: decltype(result_of(&Class::memberfunction)) */
|
||||
template<typename Base, typename Result, typename... Args>
|
||||
Result result_of(Result (Base::*func)(Args...));
|
||||
|
||||
/* usage: decay_tuple_element<0, decltype(return_args(&Class::memberfunction))> */
|
||||
template <size_t i, typename Tuple>
|
||||
using decay_tuple_element = typename std::decay<typename std::tuple_element<i, Tuple>::type>::type;
|
||||
|
||||
|
||||
struct _is_static_castable_impl
|
||||
{
|
||||
template<typename _From, typename _To, typename = decltype(static_cast<_To>(std::declval<_From>()))>
|
||||
static std::true_type __test(int);
|
||||
|
||||
template<typename, typename>
|
||||
static std::false_type __test(...);
|
||||
};
|
||||
|
||||
template<typename _From, typename _To>
|
||||
struct is_static_castable
|
||||
: public _is_static_castable_impl
|
||||
{
|
||||
typedef decltype(__test<_From, _To>(0)) type;
|
||||
};
|
||||
|
||||
template<typename _From, typename _To>
|
||||
using is_static_castable_t = typename is_static_castable<_From, _To>::type;
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
auto c = C::Create(0);
|
||||
auto d = D::Create(0);
|
||||
|
||||
typedef decay_tuple_element<0, decltype(return_args(&C::leak_private_type))> Private;
|
||||
Private::make();
|
||||
|
||||
|
||||
auto a1 = foo(0);
|
||||
auto a2 = std::shared_ptr<A>(new A({}, 0));
|
||||
|
||||
// C c1({}, 0, 0);
|
||||
}
|
38
type_name.h
Normal file
38
type_name.h
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#ifndef _MSC_VER
|
||||
# include <cxxabi.h>
|
||||
#endif
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
template <class T>
|
||||
std::string
|
||||
type_name()
|
||||
{
|
||||
typedef typename std::remove_reference<T>::type TR;
|
||||
std::unique_ptr<char, void(*)(void*)> own
|
||||
(
|
||||
#ifndef _MSC_VER
|
||||
abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr),
|
||||
#else
|
||||
nullptr,
|
||||
#endif
|
||||
std::free
|
||||
);
|
||||
std::string r = own != nullptr ? own.get() : typeid(TR).name();
|
||||
if (std::is_const<TR>::value)
|
||||
r += " const";
|
||||
if (std::is_volatile<TR>::value)
|
||||
r += " volatile";
|
||||
if (std::is_lvalue_reference<T>::value)
|
||||
r += "&";
|
||||
else if (std::is_rvalue_reference<T>::value)
|
||||
r += "&&";
|
||||
return r;
|
||||
}
|
||||
|
||||
#define TYPE_NAME(p) (type_name<decltype(p)>())
|
Loading…
Reference in New Issue
Block a user