[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