traits.hpp
4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright John Maddock 2007.
// Copyright Matt Borland 2021.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
This header defines two traits classes, both in namespace boost::math::tools.
is_distribution<D>::value is true iff D has overloaded "cdf" and
"quantile" functions, plus member typedefs value_type and policy_type.
It's not much of a definitive test frankly,
but if it looks like a distribution and quacks like a distribution
then it must be a distribution.
is_scaled_distribution<D>::value is true iff D is a distribution
as defined above, and has member functions "scale" and "location".
*/
#ifndef BOOST_STATS_IS_DISTRIBUTION_HPP
#define BOOST_STATS_IS_DISTRIBUTION_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <type_traits>
namespace boost{ namespace math{ namespace tools{
namespace detail{
#define BOOST_MATH_HAS_NAMED_TRAIT(trait, name) \
template <typename T> \
class trait \
{ \
private: \
using yes = char; \
struct no { char x[2]; }; \
\
template <typename U> \
static yes test(typename U::name* = nullptr); \
\
template <typename U> \
static no test(...); \
\
public: \
static constexpr bool value = (sizeof(test<T>(0)) == sizeof(char)); \
};
BOOST_MATH_HAS_NAMED_TRAIT(has_value_type, value_type)
BOOST_MATH_HAS_NAMED_TRAIT(has_policy_type, policy_type)
BOOST_MATH_HAS_NAMED_TRAIT(has_backend_type, backend_type)
// C++17-esque helpers
#if defined(__cpp_variable_templates) && __cpp_variable_templates >= 201304L
template <typename T>
constexpr bool has_value_type_v = has_value_type<T>::value;
template <typename T>
constexpr bool has_policy_type_v = has_policy_type<T>::value;
template <typename T>
constexpr bool has_backend_type_v = has_backend_type<T>::value;
#endif
template <typename D>
char cdf(const D& ...);
template <typename D>
char quantile(const D& ...);
template <typename D>
struct has_cdf
{
static D d;
static constexpr bool value = sizeof(cdf(d, 0.0f)) != 1;
};
template <typename D>
struct has_quantile
{
static D d;
static constexpr bool value = sizeof(quantile(d, 0.0f)) != 1;
};
template <typename D>
struct is_distribution_imp
{
static constexpr bool value =
has_quantile<D>::value
&& has_cdf<D>::value
&& has_value_type<D>::value
&& has_policy_type<D>::value;
};
template <typename sig, sig val>
struct result_tag{};
template <typename D>
double test_has_location(const volatile result_tag<typename D::value_type (D::*)()const, &D::location>*);
template <typename D>
char test_has_location(...);
template <typename D>
double test_has_scale(const volatile result_tag<typename D::value_type (D::*)()const, &D::scale>*);
template <typename D>
char test_has_scale(...);
template <typename D, bool b>
struct is_scaled_distribution_helper
{
static constexpr bool value = false;
};
template <typename D>
struct is_scaled_distribution_helper<D, true>
{
static constexpr bool value =
(sizeof(test_has_location<D>(0)) != 1)
&&
(sizeof(test_has_scale<D>(0)) != 1);
};
template <typename D>
struct is_scaled_distribution_imp
{
static constexpr bool value = (::boost::math::tools::detail::is_scaled_distribution_helper<D, ::boost::math::tools::detail::is_distribution_imp<D>::value>::value);
};
} // namespace detail
template <typename T> struct is_distribution : public std::integral_constant<bool, ::boost::math::tools::detail::is_distribution_imp<T>::value> {};
template <typename T> struct is_scaled_distribution : public std::integral_constant<bool, ::boost::math::tools::detail::is_scaled_distribution_imp<T>::value> {};
}}}
#endif