Ответ 1
Добавить field_type
объявление в шаблон флага с типом возврата auto
(доступно только после С++ 14)
Работает только в gcc 4.9:
#include <type_traits>
template<int N>
struct flag {
friend constexpr int adl_flag (flag<N>);
friend constexpr auto field_type(flag<N>);
};
template<typename T, int N>
struct writer {
friend constexpr int adl_flag (flag<N>) { return N; }
friend constexpr auto field_type(flag<N>) { return (T&&)(*(T*)0); } // remove default constructable restriction
static constexpr int value = N;
};
template<int N, class = char[noexcept(adl_flag(flag<N> ()))?+1:-1]>
int constexpr reader (int, flag<N>) { return N; }
template<int N>
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1>())) { return R; }
int constexpr reader (float, flag<0>) { return 0; }
template<typename T, int N = 1, int C = reader (0, flag<32> ())>
int constexpr next (int R = writer<T, C + N>::value) { return R; }
int main () {
constexpr int a = next<int> ();
constexpr int b = next<double> ();
constexpr int c = next<long> ();
// YES! it works!!!
static_assert (a == 1 && b == a+1 && c == b+1, "try again");
static_assert(std::is_same<decltype(field_type(flag<1>{})), int>{}, "first is int");
static_assert(std::is_same<decltype(field_type(flag<2>{})), double>{}, "second is double");
static_assert(std::is_same<decltype(field_type(flag<3>{})), long>{}, "third is long");
}
Использовать decltype автофункций вместо noexcept, работает после gcc 5.2, clang 3.5.1 - 3.7.1:
#include <type_traits>
template <int N>
struct flag {
constexpr friend auto adl_flag(flag<N>);
friend auto field_type(flag<N>);
};
template<typename T, int N>
struct writer {
friend constexpr auto adl_flag(flag<N>) { return 0; }
friend auto field_type(flag<N>) { return (T&&)(*(T*)0); }
static constexpr int value = N;
};
template<int N, class = decltype(adl_flag(flag<N>{}))>
int constexpr reader (int, flag<N>) { return N; }
template<int N>
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1>())) { return R; }
int constexpr reader (float, flag<0>) { return 0; }
template<typename T, int N = 1, int C = reader (0, flag<32> ())>
int constexpr next (int R = writer<T, C + N>::value) { return R; }
int main () {
constexpr int a = next<int> ();
constexpr int b = next<double> ();
constexpr int c = next<long> ();
// YES! it works!!!
static_assert (a == 1 && b == a+1 && c == b+1, "try again");
static_assert(std::is_same<decltype(field_type(flag<1>{})), int>{}, "first is int");
static_assert(std::is_same<decltype(field_type(flag<2>{})), double>{}, "second is double");
static_assert(std::is_same<decltype(field_type(flag<3>{})), long>{}, "third is long");
}