Я бы сделал так:
#include <experimental/type_traits>
using std::experimental::is_detected;
template <typename T, typename U>
using plus_equal_t = decltype(std::declval<T&>() += std::declval<U>());
template <typename T, typename U>
using time_equal_t = decltype(std::declval<T&>() += std::declval<U>());
// Define traits
template <typename T, typename U>
using has_plus_equal = is_detected<plus_equal_t, T, U>;
template <typename T, typename U>
using has_time_equal = is_detected<time_equal_t, T, U>;
template<typename T>
struct Weighted {
double weight;
T value;
// ...
// weighted mean
template<typename U=T,
std::enable_if_t<has_plus_equal<U, U>::value
&& has_time_equal<U, double>::value, int> = 0>
Weighted& operator+=(const Weighted<T>& other) {
value *= weight;
value += other.weight*other.value;
weight += other.weight;
value /= weight;
return *this;
}
// ...
};
А в C ++ 2a упростите его до:
Weighted& operator+=(const Weighted<T>& other)
requires(has_plus_equal<T, T>::value && has_time_equal<T, double>::value)
{ /*..*/ }