I'm following the How to implement a constant-expression counter in C++ tutorial and I'm trying to fix the C++14 Reflections Without Macros, Markup nor External Tooling talk limitations.
The basic idea of the tutorial is this:
template<int N>
struct flag {
friend constexpr int adl_flag (flag<N>);
};
template<int N>
struct writer {
friend constexpr int adl_flag (flag<N>) { return N; }
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<int N = 1, int C = reader (0, flag<32> ())>
int constexpr next (int R = writer<C + N>::value) { return R; }
int main () {
constexpr int a = next ();
constexpr int b = next ();
constexpr int c = next ();
// YES! it works!!!
static_assert (a == 1 && b == a+1 && c == b+1, "try again");
}
Note: If you are not interested by now, it's a good time to stop reading :-)
And the talk explains how to extract number of fields and fields types for POD types using aggregate initialization and implicit conversion operator, but the major limitation is that only primitive types are supported.
I've provided the above background to justify my motivations!
When I combined these two approaches I came to this:
template<int N>
struct flag {
friend constexpr int adl_flag (flag<N>);
};
template<typename T, int N>
struct writer {
friend constexpr int adl_flag (flag<N>) {
return N;
}
friend constexpr T field_type(flag<N>) { return T{}; }
static constexpr int value = N;
};
The field_type(flag<N>)
will give me the type of N
th field.
Note that it's a friend function and for the N
th field of a POD
type exactly one field_type(flag<N>)
will be defined by the compiler.
g++
gives me no matching function for call to 'field_type(flag<1>)
for decltype(field_type(flag<1>))
.
I need to somehow force ADL
to search in all instances of writer<T,N>
.
How can I do that?
Update
As @T.C.mentioned ADL only looks into associated classes, and writer
isn't one. (That's why adl_flag
is declared in flag
- so that ADL
could find it.)
How can I make writer
an associated class without knowing the T
value so that ADL
can find it?
writer
isn't one. (That's whyadl_flag
is declared inflag
- so that ADL could find it.) – Watersoakthe committee is going to ban the whole counter thing
Can please give a reference that indicate that's their intention? The ADL rules that meta-counter uses are old. How committee is going to change the rules without possibly breaking millions of code lines! – GalwayODR
mistake in the last line of question, i meantADL
:-) – Galwaynoexcept
stuff you added differs from the original post. – Jonettenoexcept
is actually the "Workaround for VC++", listed at the end of the linked page. Try it with the Visual C++ online compiler, and it works. Basically, it compensates for MSVC's spotty implementation of: SFINAE, aggregate initialisation in constant expressions, and re-evaluation of expressions used as both template parameters & function parameter default values in the same function. – Shipway