Add template type checking for EventMetric.

Add template var arg type checking for EventMetric.

This change adds some type checking for the variable argument
EventMetric which assures that there are no mismatches between
the definition of an EventMetric instance and the overloaded
constructor.

This is a merge from wvgerrit/28424.

BUG: 34846989
Test: Manually verified appropriate compile time errors.
Change-Id: I3e501abf76b78211f9cef19960ef11c179a0ff93
This commit is contained in:
Adam Stone
2017-06-14 10:10:53 -07:00
parent 80a95a1b64
commit 0963400d57

View File

@@ -238,20 +238,57 @@ inline void AppendFieldNames(std::vector<std::string>* field_name_vector,
va_end(field_names);
}
// These helper methods and FirstUnusedType assure that there is no mismatch
// between the specified types for EventMetrics and the constructors and
// methods used for the specializations.
template <bool>
struct CompileAssert {};
#define COMPILE_ASSERT(expr, msg) \
typedef impl::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
template <typename T> struct is_unused { static const bool value = false; };
template <> struct is_unused<Unused> { static const bool value = true; };
template <typename F1, typename F2, typename F3, typename F4>
class FirstUnusedType {
static const bool a = is_unused<F1>::value;
static const bool b = is_unused<F2>::value;
static const bool c = is_unused<F3>::value;
static const bool d = is_unused<F4>::value;
// Check that all types after the first Unused are also Unused.
COMPILE_ASSERT(a <= b, Invalid_Unused_At_Position_2);
COMPILE_ASSERT(b <= c, Invalid_Unused_At_Position_3);
COMPILE_ASSERT(c <= d, Invalid_Unused_At_Position_4);
public:
static const int value = 5 - (a + b + c + d);
};
// Asserts that no Unused types exist before N; after N, are all Unused types.
#define ASSERT_METRIC_UNUSED_START_FROM(N) \
COMPILE_ASSERT((\
impl::FirstUnusedType<F1, F2, F3, F4>::value) == N, \
Unused_Start_From_##N)
} // namespace impl
// Overloaded template constructor implementations for EventMetric.
template<typename F1, typename F2, typename F3, typename F4>
EventMetric<F1, F2, F3, F4>::EventMetric(
const std::string& metric_name)
: BaseEventMetric(metric_name) {}
: BaseEventMetric(metric_name) {
ASSERT_METRIC_UNUSED_START_FROM(1);
}
template<typename F1, typename F2, typename F3, typename F4>
EventMetric<F1, F2, F3, F4>::EventMetric(
const std::string& metric_name,
const char* field_name)
: BaseEventMetric(metric_name) {
impl::AppendFieldNames(&field_names_, 1, field_name);
ASSERT_METRIC_UNUSED_START_FROM(2);
impl::AppendFieldNames(&field_names_,
impl::FirstUnusedType<F1, F2, F3, F4>::value - 1,
field_name);
}
template<typename F1, typename F2, typename F3, typename F4>
EventMetric<F1, F2, F3, F4>::EventMetric(
@@ -259,7 +296,10 @@ EventMetric<F1, F2, F3, F4>::EventMetric(
const char* field_name1,
const char* field_name2)
: BaseEventMetric(metric_name) {
impl::AppendFieldNames(&field_names_, 2, field_name1, field_name2);
ASSERT_METRIC_UNUSED_START_FROM(3);
impl::AppendFieldNames(&field_names_,
impl::FirstUnusedType<F1, F2, F3, F4>::value - 1,
field_name1, field_name2);
}
template<typename F1, typename F2, typename F3, typename F4>
EventMetric<F1, F2, F3, F4>::EventMetric(
@@ -268,8 +308,10 @@ EventMetric<F1, F2, F3, F4>::EventMetric(
const char* field_name2,
const char* field_name3)
: BaseEventMetric(metric_name) {
ASSERT_METRIC_UNUSED_START_FROM(4);
impl::AppendFieldNames(&field_names_,
3, field_name1, field_name2, field_name3);
impl::FirstUnusedType<F1, F2, F3, F4>::value - 1,
field_name1, field_name2, field_name3);
}
template<typename F1, typename F2, typename F3, typename F4>
EventMetric<F1, F2, F3, F4>::EventMetric(
@@ -279,8 +321,10 @@ EventMetric<F1, F2, F3, F4>::EventMetric(
const char* field_name3,
const char* field_name4)
: BaseEventMetric(metric_name) {
ASSERT_METRIC_UNUSED_START_FROM(5);
impl::AppendFieldNames(&field_names_,
4, field_name1, field_name2,
impl::FirstUnusedType<F1, F2, F3, F4>::value - 1,
field_name1, field_name2,
field_name3, field_name4);
}