Topic: Variadic templates again
Author: "jam" <farid.mehrabi@gmail.com>
Date: Fri, 9 Mar 2007 15:47:37 CST Raw View
Continuing my last post on this topic:
http://groups.google.com/group/comp.std.c++/browse_frm/thread/4f83fd008df5777b/6f1c21e791c1542e?lnk=gst&q=variadic+templates&rnum=7&hl=en#6f1c21e791c1542e
Mr Douglas Gregor and I had a virtual personal discussion about
variadic template syntax which we decided to share on comp.std.c+
+.Here it goes:
>>On Feb 3, 2007, at 4:10 AM, Farid Mehrabi wrote:
>>considering:
>>template <typename ty> class A;
>>I prefer the following syntax :
>>A<ret_type (*)(args...)>
>>to the newly suggested syntax :
>>A<ret_type(args...)>
>The type parameter in the first one is function pointer type, and a function type in the second >one. What part of this syntax don't you like?
Do you mean that C++ should define a new unnamed template type for
functions?
What are the specifications of such a type?
Is it only intended to break a parameter pack into a single
parameter('ret_type') and the rest ('args')?
If this is the case then having either pseudo typedef or the
combination of member unpacking with class packing(ie packing data
members of class/struct/union into the parameter pack) can
move the problem from compiler syntax design to library design ,making
it more flexible and comprehensible:
/*Do this*/
template <typename unused>class funxniod{/*emplty definition*/};
template <typename ret_type,typename ... Targs>
class funxniod < ret_type (*) ( Targs ...) >
{ //specialized for function pointers
typedef ret_type ret_type;
//either:
typedef Targs ... Targs;
//or:
struct data{
Targs ... args;
};
};
/*or do this one:*/
template <typname ret_type , typename... Targs>
struct funxn_param_pack{
typedef ret_type ret_type;
//either:
typedef Targs ... Targs;
//or:
struct data{
Targs ... args;
};
};
/*or even do this:*/
template < typename... Targs>
struct Params {
//either:
typedef Targs ... Targs;
//or:
struct data{
Targs ... args;
};
};
template < typename ret_type , typename paramlist >
struct funxn_object{
typedef ret_type ret_type;
//either:
typedef typename paramlist::Targs ... Targs;
//or:
typedef typename paramlist::data data;
};
template < typename funxn_type>
struct a_tmplt:
funxn_type
{
typedef typename funxn_type::ret_type ret_type;
//either:
typedef typename funxn_type::Targs ... Targs;
ret_type operator()(Targs ...args);
//or:
typedef typename funxn_type::data data;
ret_type call({data}...args);
};
/*now use it like this:*/
tmplt < funxnoid < int (*) (double) > > obj1;
/*or use it like this:*/
tmplt < funxn_param_pack <int,double> > obj2;
/*or even use it like this:*/
tmplt < funxn_object < int , Params < double > > obj3;
>>The aforementioned pdf links state that the packed argument to a variadic templte should be >>the last one,but I do not see any reason for it : In contrast to C style variadic functions in >>which the number of parameters is not evaluated at compile time and the none-packed >>parameters need to be placed at the top of the stack,for templates the number of elements is >>caculated at compile time and such a limitation seems unnecessary.
>It's necessary when one wants to deduce the types from an argument list; it's a little bit too strict >for general expansion of parameter packs into function types.
Why?I do not agree. Words like 'It is necessary','It is strict'... do
not clarify the reason.Take this:
template < typename A, typename B, typename ... Targs, typename C >
stuct variadic;
Given the above template declaration we know that every instansiation
of it needs at least 3 type parameters, two of which appearing at the
beginning and one in the end.So there will not be any problem deducing
template parameters for the following line:
variadic < T1,T2,T4,T3> v1;
It is obvious that parameters appearing at the right side of the pack
must not introduce default arguments or the compiler reports error.But
I can suggest a syntax trick for that too:
template <
typename A,
typename B,
typename ... Targs={int,double}, /*new syntax ;This will not produce
syntax conflicts*/
typename C=char
>
stuct variadic{};
variadic < T1,T2,{float}> vtt_f;//ok:Targs={float},C=char
variadic < T1,T2> vtt_id_c ;//ok:Targs={int,double}, C=char
variadic < T1,T2,float> vtt_f;//ok:Targs={float},C=char
variadic < T1,T2,{},T3> vtt__t;//ok:Targs={/*no param*/},C=T3
variadic < T1,T2, T3,T4> vtt_er;//error:can not deduce parameters.
variadic < T1,T2,{T4},T3> vtt_t_t;//ok:Targs={T4},C=T3
The above syntax is necessary for variadic templates with parameter
packs preceeding a parameter with default argument.It also can provide
syntactic potential for multiple parameter packed templates:
template < typename ... T1,typename ... T2>class impractical;
impractical<{int},{int,double} > imp; //T1=int,T2=int,double
>>unpacking control:
>>template<typename...> struct Tuple {};
>>template<typename T1, typename T2> struct Pair {};
>>template<typename... Args1>
>>struct zip {
>>template<typename... Args2>
>>struct with {
>>typedef Tuple<Pair<{Args1}/*prevent unpacking*/
>> ,Args2>...
>> {Args1...}/*unpack now*/
>> >
>> type;
>> };
>>};
>>Here the number of arguments to 'tuple' is 'sizeof...(Args1)*sizeof...(Args2)'.
>It's an interesting idea. There's at least one syntactic collision here, because { Args1... } is using >the same syntax as unpacking into an initializer list. For this particular case, the compiler could >figure it out (one can't expand types as initializers), if Args1 were a non-type template >parameter pack, we would need another syntactic trick to make this work.
The solution is still brackets but since curly {} braces are
problematic , we can use other brackets . I suggest either square []
or angle <> brackets . First of which is easier to use but the second
though interfering with shift operators and the need for correct
spacing ,provide better syntax integrity with templates (or maybe we
should replace angle brackets of templates with square ones
increasing syntax integrity with built-in arrays and removing the
need for 'template' keyword):
typedef Tuple<Pair< < Args1 > , Args2 > ... <Args1... > > type;
>>I suggest reverse unpacking to be added to the syntax:
>>template<typename... TArgs>
>>void forward__unpack(TArgs... vargs );/*vargs are unpacked in the same order as declaration >>of TArgs*/
>>template<typename... TArgs>
>>void backward_unpack(/*HERE*/...TArgs vargs );/*vargs are unpacked in the reverse order >>of declaration of TArgs*/
>>class A{};
>>int main(){
>> int i=1;A a;
>> forward__unpack<int,a>(i,a);
>> backward_unpack<int,a>(a,i);/*HERE*/
>>return 0;
>>};
>It seems to me that if we're going to allow reversing the sequence, we should do so only when >unpacking.
Exactly.
>>It is better to add Pseudo typedef instructions for argument packs:
>>template<typename... TArgs>
>>struct variadic{
>> typedef TArgs... same_Args;
>> typedef ...TArgs reverse_Args;
>>};
>Anything that involves making a parameter pack into a member of a class becomes very, very >complicated, very quickly.
>>data storage:
>>For one reason or another one might need to store and retrieve a packed parameter to and from >>memory.I have two suggestions for this:
>>I-member unpacking:
>>template<typename... TArgs>
>>struct variadic{
>> struct forward__pack{
>> int i;
>> TArgs... vargs;
>> };
>> struct backward_pack{
>> int i;
>> ...TArgs vargs;
>> };
>>};
>Same problem as before: once you have parameter packs as members, the syntax becomes >immediately unwieldy. We've thought it was a good idea, we thought it could be done, but the >pain of making it work---both for users and for compilers---is far greater than the benefits one >gains from this.
Please describe it more. My intention is to be able to unpack a
parameter pack into a data type one way or other - so that for example
one can store/retrieve it onto/from the heap - and repack it as a
parameter pack again in order to be passed to another template .
Especially , I want the parameter pack to be inheritable which means
that it should become a member somehow.Now take this syntax:
template<typename... Targs>
struct variadic{
typedef struct {...const Targs *} Sargs;/*unpack const Targs* to
Sargs in reverse order*/
void go(const Targs ... vargs){
Sargs s={...&vargs};//initiatialize s with pointers to vargs` elements
If(false)//compile but never run
go(*[...s]);//dereference s back to Targs and unpack
};
};
>>II-we must be able to treat every class/struct/union whose data members are accessible >>acording to access rules,as a parameter pack:
>>template<typename... TArgs>
>>struct cap{
>> static void go(TArgs... vargs);
>>};
>>class A{
>> int private_i;
>> double private_d;
>>public:
>> void go(A a){
>> cap<{A}...>::go({a}...)/*new syntax with forward packing:call cap<int,double>::go(i,d)*/
>> cap<...{A}>::go(...{a})/*new syntax with backward packing:call cap<double,int>::go(d,i)*/
>> };
>>};
>That's an interesting idea, and it would make some tasks (reflection, serialization) quite a bit >easier. There's still the issue that {a} is an initializer list, so the syntax itself would need to >change.
>Why does {A}... return a parameter pack containing only the types of the members of A? I >would have expected, perhaps, member pointers.
First: Please do not get confused; reflection in C++ is another
story(read tragedy).
Second:Replace 'A' with a type template Parameter:
template <class B>
void go(B a){
A*__unused (&a);// compile time type checking.
cap< [B...] >::go([a...]);//square[] brackets instead of curly{}
ones.
cap< [...B] >::go( [...a]);
};
>>Finally a variadic template must be able to have a defualt parametr pack:
>>struct A;
>>template<typename... Targs=A,int> struct variadic1;
>This syntax would produce some syntactic and semantic collisions. Turn "variadic1" into a >function template, like this:
> template<typename... Targs=A,int> void foo();
>Does that mean that the default parameter for Targs is A, int; or is the default parameter for >Targs A and is there a second, unnamed "int" template non-type parameter?
Change syntax:
template<typename... Targs={A,int}> > struct variadic1;
template<typename... Targs={A,int} > void foo();
template<typename... Targs=[A...] > struct variadic2;//struct A is
packed as a parameter pack
regards
FM
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "jam" <farid.mehrabi@gmail.com>
Date: Fri, 9 Mar 2007 17:25:52 CST Raw View
Following my last post on this topic:
http://groups.google.com/group/comp.std.c++/browse_frm/thread/4f83fd008df5777b/6f1c21e791c1542e?lnk=gst&q=variadic+templates&rnum=7&hl=en#6f1c21e791c1542e
Mr Douglas Gregor and I had a virtual personal discussion about
variadic template (see)syntax which we decided to share on comp.std.c+
+.Here it goes:
>>On Feb 3, 2007, at 4:10 AM, Farid Mehrabi wrote:
>>considering:
>>template <typename ty> class A;
>>I prefer the following syntax :
>>A<ret_type (*)(args...)>
>>to the newly suggested syntax :
>>A<ret_type(args...)>
>The type parameter in the first one is function pointer type, and a function type in the second >one. What part of this syntax don't you like?
Do you mean that C++ should define a new unnamed template type for
functions?
What are the specifications of such a type?
Is it only intended to break a parameter pack into a single
parameter('ret_type') and the rest ('args')?
If this is the case then having either pseudo typedef or the
combination of member unpacking with class packing(ie packing data
members of class/struct/union into the parameter pack) can
move the problem from compiler syntax design to library design ,making
it more flexible and comprehensible:
/*Do this*/
template <typename unused>class funxniod{/*emplty definition*/};
template <typename ret_type,typename ... Targs>
class funxniod < ret_type (*) ( Targs ...) >
{ //specialized for function pointers
typedef ret_type ret_type;
//either:
typedef Targs ... Targs;
//or:
struct data{
Targs ... args;
};
};
/*or do this one:*/
template <typname ret_type , typename... Targs>
struct funxn_param_pack{
typedef ret_type ret_type;
//either:
typedef Targs ... Targs;
//or:
struct data{
Targs ... args;
};
};
/*or even do this:*/
template < typename... Targs>
struct Params {
//either:
typedef Targs ... Targs;
//or:
struct data{
Targs ... args;
};
};
template < typename ret_type , typename paramlist >
struct funxn_object{
typedef ret_type ret_type;
//either:
typedef typename paramlist::Targs ... Targs;
//or:
typedef typename paramlist::data data;
};
template < typename funxn_type>
struct a_tmplt:
funxn_type
{
typedef typename funxn_type::ret_type ret_type;
//either:
typedef typename funxn_type::Targs ... Targs;
ret_type operator()(Targs ...args);
//or:
typedef typename funxn_type::data data;
ret_type call({data}...args);
};
/*now use it like this:*/
tmplt < funxnoid < int (*) (double) > > obj1;
/*or use it like this:*/
tmplt < funxn_param_pack <int,double> > obj2;
/*or even use it like this:*/
tmplt < funxn_object < int , Params < double > > obj3;
>>The aforementioned pdf links state that the packed argument to a variadic templte should be >>the last one,but I do not see any reason for it : In contrast to C style variadic functions in >>which the number of parameters is not evaluated at compile time and the none-packed >>parameters need to be placed at the top of the stack,for templates the number of elements is >>caculated at compile time and such a limitation seems unnecessary.
>It's necessary when one wants to deduce the types from an argument list; it's a little bit too strict >for general expansion of parameter packs into function types.
Why?I do not agree. Words like 'It is necessary','It is strict'... do
not clarify the reason.Take this:
template < typename A, typename B, typename ... Targs, typename C >
stuct variadic;
Given the above template declaration we know that every instansiation
of it needs at least 3 type parameters, two of which appearing at the
beginning and one in the end.So there will not be any problem deducing
template parameters for the following line:
variadic < T1,T2,T4,T3> v1;
It is obvious that parameters appearing at the right side of the pack
must not introduce default arguments or the compiler reports error.But
I can suggest a syntax trick for that too:
template <
typename A,
typename B,
typename ... Targs={int,double}, /*new syntax ;This will not produce
syntax conflicts*/
typename C=char
>
stuct variadic{};
variadic < T1,T2,{float}> vtt_f;//ok:Targs={float},C=char
variadic < T1,T2> vtt_id_c ;//ok:Targs={int,double}, C=char
variadic < T1,T2,float> vtt_f;//ok:Targs={float},C=char
variadic < T1,T2,{},T3> vtt__t;//ok:Targs={/*no param*/},C=T3
variadic < T1,T2, T3,T4> vtt_er;//error:can not deduce parameters.
variadic < T1,T2,{T4},T3> vtt_t_t;//ok:Targs={T4},C=T3
The above syntax is necessary for variadic templates with parameter
packs preceeding a parameter with default argument.It also can provide
syntactic potential for multiple parameter packed templates:
template < typename ... T1,typename ... T2>class impractical;
impractical<{int},{int,double} > imp; //T1=int,T2=int,double
>>unpacking control:
>>template<typename...> struct Tuple {};
>>template<typename T1, typename T2> struct Pair {};
>>template<typename... Args1>
>>struct zip {
>>template<typename... Args2>
>>struct with {
>>typedef Tuple<Pair<{Args1}/*prevent unpacking*/
>> ,Args2>...
>> {Args1...}/*unpack now*/
>> >
>> type;
>> };
>>};
>>Here the number of arguments to 'tuple' is 'sizeof...(Args1)*sizeof...(Args2)'.
>It's an interesting idea. There's at least one syntactic collision here, because { Args1... } is using >the same syntax as unpacking into an initializer list. For this particular case, the compiler could >figure it out (one can't expand types as initializers), if Args1 were a non-type template >parameter pack, we would need another syntactic trick to make this work.
The solution is still brackets but since curly {} braces are
problematic , we can use other brackets . I suggest either square []
or angle <> brackets . First of which is easier to use but the second
though interfering with shift operators and the need for correct
spacing ,provide better syntax integrity with templates (or maybe we
should replace angle brackets of templates with square ones
increasing syntax integrity with built-in arrays and removing the
need for 'template' keyword):
typedef Tuple<Pair< < Args1 > , Args2 > ... <Args1... > > type;
>>I suggest reverse unpacking to be added to the syntax:
>>template<typename... TArgs>
>>void forward__unpack(TArgs... vargs );/*vargs are unpacked in the same order as declaration >>of TArgs*/
>>template<typename... TArgs>
>>void backward_unpack(/*HERE*/...TArgs vargs );/*vargs are unpacked in the reverse order >>of declaration of TArgs*/
>>class A{};
>>int main(){
>> int i=1;A a;
>> forward__unpack<int,a>(i,a);
>> backward_unpack<int,a>(a,i);/*HERE*/
>>return 0;
>>};
>It seems to me that if we're going to allow reversing the sequence, we should do so only when >unpacking.
Exactly.
>>It is better to add Pseudo typedef instructions for argument packs:
>>template<typename... TArgs>
>>struct variadic{
>> typedef TArgs... same_Args;
>> typedef ...TArgs reverse_Args;
>>};
>Anything that involves making a parameter pack into a member of a class becomes very, very >complicated, very quickly.
>>data storage:
>>For one reason or another one might need to store and retrieve a packed parameter to and from >>memory.I have two suggestions for this:
>>I-member unpacking:
>>template<typename... TArgs>
>>struct variadic{
>> struct forward__pack{
>> int i;
>> TArgs... vargs;
>> };
>> struct backward_pack{
>> int i;
>> ...TArgs vargs;
>> };
>>};
>Same problem as before: once you have parameter packs as members, the syntax becomes >immediately unwieldy. We've thought it was a good idea, we thought it could be done, but the >pain of making it work---both for users and for compilers---is far greater than the benefits one >gains from this.
Please describe it more. My intention is to be able to unpack a
parameter pack into a data type one way or other - so that for example
one can store/retrieve it onto/from the heap - and repack it as a
parameter pack again in order to be passed to another template .
Especially , I want the parameter pack to be inheritable which means
that it should become a member somehow.Now take this syntax:
template<typename... Targs>
struct variadic{
typedef struct {...const Targs *} Sargs;/*unpack const Targs* to
Sargs in reverse order*/
void go(const Targs ... vargs){
Sargs s={...&vargs};//initiatialize s with pointers to vargs` elements
If(false)//compile but never run
go(*[...s]);//dereference s back to Targs and unpack
};
};
>>II-we must be able to treat every class/struct/union whose data members are accessible >>acording to access rules,as a parameter pack:
>>template<typename... TArgs>
>>struct cap{
>> static void go(TArgs... vargs);
>>};
>>class A{
>> int private_i;
>> double private_d;
>>public:
>> void go(A a){
>> cap<{A}...>::go({a}...)/*new syntax with forward packing:call cap<int,double>::go(i,d)*/
>> cap<...{A}>::go(...{a})/*new syntax with backward packing:call cap<double,int>::go(d,i)*/
>> };
>>};
>That's an interesting idea, and it would make some tasks (reflection, serialization) quite a bit >easier. There's still the issue that {a} is an initializer list, so the syntax itself would need to >change.
>Why does {A}... return a parameter pack containing only the types of the members of A? I >would have expected, perhaps, member pointers.
First: Do not get confused reflection in C++ is another story(read
tragedy).
Second:Replace 'A' with a type template Parameter:
template <class B>
void go(B a){
A*__unused (&a);// compile time type checking.
cap< [B...] >::go([a...]);//square[] brackets instead of curly{}
ones.
cap< [...B] >::go( [...a]);
};
>>Finally a variadic template must be able to have a defualt parametr pack:
>>struct A;
>>template<typename... Targs=A,int> struct variadic1;
>This syntax would produce some syntactic and semantic collisions. Turn "variadic1" into a >function template, like this:
> template<typename... Targs=A,int> void foo();
>Does that mean that the default parameter for Targs is A, int; or is the default parameter for >Targs A and is there a second, unnamed "int" template non-type parameter?
Change syntax:
template<typename... Targs={A,int}> > struct variadic1;
template<typename... Targs={A,int} > void foo();
template<typename... Targs=[A...] > struct variadic2;//struct A is
packed as a parameter pack
regards
FM
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Douglas Gregor" <doug.gregor@gmail.com>
Date: Mon, 12 Mar 2007 13:27:47 CST Raw View
On Mar 9, 7:25 pm, "jam" <farid.mehr...@gmail.com> wrote:
> >>On Feb 3, 2007, at 4:10 AM, Farid Mehrabi wrote:
> >>considering:
> >>template <typename ty> class A;
> >>I prefer the following syntax :
> >>A<ret_type (*)(args...)>
> >>to the newly suggested syntax :
> >>A<ret_type(args...)>
> >The type parameter in the first one is function pointer type, and a function type in the second >one. What part of this syntax don't you like?
>
> Do you mean that C++ should define a new unnamed template type for
> functions?
I haven't proposed anything new. You can already write a function
type, using the syntax above. For example, one could write:
template<typename Sig> struct function_traits;
template<typename R, typename T1, typename T2>
struct function_traits<R(T1, T2)> { // okay, matches any unqualified
function type with two parameters
typedef R result_type;
}%3
Variadic templates just make it possible to abstract that function
type to work with an arbitrary number of parameters.
> template <typename ret_type,typename ... Targs>
> class funxniod < ret_type (*) ( Targs ...) >
> { //specialized for function pointers
> typedef ret_type ret_type;
> //either:
> typedef Targs ... Targs;
> //or:
> struct data{
> Targs ... args;
> };
>
> };
Anything that involves unpacking a parameter pack as separate members
in a class or struct is a problem. It's not unsurmountable, certainly,
but this extension brings a large number of complications stemming
from the simple question, "is typename funxniod<Sig>::Targs is type or
a type parameter pack?" It could be a type in one specialization, and
a parameter pack in another specialization, so you need a syntax to
tell the compiler "this is a parameter pack." I've not seen a
suggested syntax that didn't double the syntactic weight of variadic
templates.
> >>The aforementioned pdf links state that the packed argument to a variadic templte should be >>the last one,but I do not see any reason for it : In contrast to C style variadic functions in >>which the number of parameters is not not evaluated at compile time and the none-packed >>parameters need to be placed at the top of the stack,for templates the number of elements is >>caculated at compile time and such a limitation seems unnecessary.
> >It's necessary when one wants to deduce the types from an argument list; it's a little bit too strict >for general expansion of parameter packs into function types.
>
> Why?I do not agree. Words like 'It is necessary','It is strict'... do
> not clarify the reason.Take this:
>
> template < typename A, typename B, typename ... Targs, typename C >
> stuct variadic;
>
> Given the above template declaration we know that every instansiation
> of it needs at least 3 type parameters, two of which appearing at the
> beginning and one in the end.So there will not be any problem deducing
> template parameters for the following line:
>
> variadic < T1,T2,T4,T3> v1;
Sure, you can make it work in this trivial example. The problem is
that it doesn't generalize well. Just for kicks:
template<typename... Args> struct foo;
template<typename... Args1, typename T, typename... Args2,
typename... Args3>
struct foo<Args1&.., T&, Args2&.., T, Args3...> { ... }
foo<int&, float&, 26, float&, double&, string&, int, float&,
double&, double&> x; // how's this match the partial specialization?
> It is obvious that parameters appearing at the right side of the pack
> must not introduce default arguments or the compiler reports error.But
> I can suggest a syntax trick for that too:
>
> template <
> typename A,
> typename B,
> typename ... Targs={int,double}, /*new syntax ;This will not produce
> syntax conflicts*/
> typename C=char
Sure, that's possible.
> The above syntax is necessary for variadic templates with parameter
> packs preceeding a parameter with default argument.
But it's unnecessary if one cannot have parameter packs preceeding a
parameter with a default argument. This is partly what I meant by the
syntactic weight of variadic templates growing drastically as we add
features... by removing the "old allow expansion at the end" rule,
we've made template argument deduction much more complicated (the
"foo" example), and forced ourselves to add yet more features.
> It also can provide
> syntactic potential for multiple parameter packed templates:
>
> template < typename ... T1,typename ... T2>class impractical;
>
> impracpracl<{int},{int,double} > imp; //T1=int,T2=int,double
>
> >>unpacking control:
> >>template<typename...> struct Tuple {};
> >>template<typename T1, typename T2> struct Pair {};
> >>template<typename... Args1>
> >>struct zip {
>
> >>template<typename... Args2>
> >>struct with {
> >>typedef Tuple<Pair<{Args1}/*prevent unpacking*/
> >> ,Args2>...
> >> {Args1...}/*unpack now*/
> >> >
> >> type;
>
> >> };
> >>};
> >>Here the number of arguments to 'tuple' is 'sizeof...(Args1)*sizeof...(Args2)'.
> >It's an interesting idea. There's at least one syntactic collision here, because { Args1... } is using >the same syntax as unpacking into an initializer list. For this particular case, the compiler could >figure it out (one can't expand types as initializers), if Args1 were a non-type template >parameter pack, we would need another syntactic trick to make this work.
>
> The solution is still brackets but since curly {} braces are
> problematic , we can use other brackets . I suggest either square []
> or angle <> brackets . First of which is eas easier to use but the second
> though interfering with shift operators and the need for correct
> spacing ,provide better syntax integrity with templates
My impression is that angle brackets will introduce yet more syntactic
ambiguities. Square brackets could work, I think, although you are
likely to hit syntactic ambiguities with array times (int[N][M], where
M is a non-type template parameter pack).
> (or maybe we
> should replace angle brackets of templates with square ones
> increasing syntax integrity with built-in arrays and removing the
> need for 'template' keyword):
That's never going to happen. C++ syntax is here to stay, and we need
to do our best to keep our extensions minimal.
> Please describe it more.
I mentioned it again, above. Think about the reasons why we need
"typename" in "typename iterator_traits<Iterator>::value_type": it's
because, given just "iterator_traits<Iterator>::value_type", the
compiler can't know whether value_type will end up being a type or a
value. If we can expand a parameter pack as members, or into a
typedef, the exact same problem occurs: we need the equivalent of
"typename" to say that something is (or isn't) a parameter pack.
> My intention is to be able to unpack a
> parameter pack into a data type one way or other - so that for example
> one can store/retrieve it onto/from the heap - and repack it as a
> parameter pack again in order to be passed to another template .
> Especially , I want the parameter pack to be inheritable which means
> that it should become a member somehow.
You can expand a parameter pack into a base specifier list, and you
can use the standard "tuple" type for data storage. Perhaps it's not
as convenient as having a specific feature tailored for what you want
to do, but it's serviceable and it doesn't require extending the
language further.
Cheers,
Doug
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]