[cfe-dev] How to tell if a normal template is passed a parameter pack?
Ryan Johnson
scovich at gmail.com
Thu Jul 23 08:30:18 PDT 2015
Hi all,
Short version:
I have implemented a new operator similar to sizeof() or
alignof()---call it foo()---and have the following code:
template <typename... Ts>
struct A {
static constexpr size_t const values[] = {foo(Ts)...};
};
template <typename T, size_t N=foo(T)>
constexpr size_t const foo_value= N;
template <typename... Ts>
struct B {
static constexpr size_t const values[] = {foo_value<Ts>...};
};
It so happens that clang::FooExpr--which represents foo()
internally---changes its behavior depending on whether it was passed a
scalar parameter (e.g. foo_value) or a parameter pack (e.g. struct A).
Context for that given below.
THE QUESTION: is there a way FooExpr can detect that foo() is indirectly
dealing with a parameter pack when struct B passes a parameter pack to
foo_value?
(please CC me in replies)
(details and context below for the interested reader)
Thoughts?
Ryan Johnson
What I've tried so far:
It's easy enough to detect from
Parser::ParseUnaryExprOrTypeTraitExpression() that struct A directly
passes an unexpanded parameter pack to foo(), and it's equally easy to
detect that foo_value directly passes a scalar parameter to foo().
Detecting the indirect parameter pack obviously can't be done when
foo_value is parsed, though, and I can't figure out how to make it
notice later that the initial scalar parameter passed by the foo_value
template is actually an unexpanded parameter pack when struct B uses it.
I suspect TreeTranstform<Derived>::TransformFooExpr(FooExpr *E) would be
the correct place for this sort of analysis, but all the macro-powered
code that drives TreeTransform is making it hard for me to tell how I
might go about that (or whether it's even possible). Having failed to
find an answer source diving, I was hoping somebody could give some
pointers of where to look and/or how to approach this problem?
Longer version, with context and motivation:
I have successfully implemented a new built-in function, __indexof(),
which is similar to sizeof...() in that it takes an argument pack and
returns a size_t. However, __indexof() is magical in that it returns a
different value for each member of the pack during expansion---namely
that member's position in the expansion:
template <typename... Ts>
struct indexes {
static constexpr const size_t values[] = {__indexof(Ts)...};
// ^^^ values[] = {0, 1, 2, ...}
};
I'm hoping to propose this as a new C++17 feature [1], and it would be
very nice if it were possible to wrap the magic __indexof() operator in
a variable template like this:
template <typename T, size_t N=__indexof(T)>
constexpr size_t const indexof = N;
... to hide the scary/magical __indexof(T) behind a normal-looking
template facade.
Unfortunately, I'm having trouble figuring out how to go about this,
because the indexof template variable thinks it is dealing with a scalar
parameter, not a parameter pack. I implemented __indexof() by studying
the implementations of sizeof...() and C++17 fold expressions, but
neither of them applies in this case and my attempts at source diving
have not turned up an answer.
[1]
https://groups.google.com/a/isocpp.org/forum/?fromgroups=#!topic/std-proposals/u9XLfRCKzGc
More information about the cfe-dev
mailing list