Prev: How to obtain a typedef for the unsigned version of a signed character type
Next: How to obtain a typedef for the unsigned version of a signed character type
From: PGK on 7 Mar 2010 08:33 I'd like to define a method which takes twice (say) the number of template parameters which define the class. The following class attempts to use explicit recursion for this, but fails. Does anyone know if this is possible? template <typename Type, typename ... Types> struct Foo { void bar(Type t1, Type t2) { std::cout << t1 << " " << t2 << std::endl; } void bar(Type t1, Type t2, Types ... ts) { std::cout << t1 << " " << t2 << std::endl; bar(ts...); } }; Many thanks, Graham -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Daniel Krügler on 7 Mar 2010 16:03 On 8 Mrz., 02:33, PGK <graham.k...(a)gmail.com> wrote: > I'd like to define a method which takes twice (say) the number of > template parameters which define the class. The following class > attempts to use explicit recursion for this, but fails. Does anyone > know if this is possible? > > template <typename Type, typename ... Types> > struct Foo { > void bar(Type t1, Type t2) { std::cout << t1 << " " << t2 << > std::endl; } > void bar(Type t1, Type t2, Types ... ts) { > std::cout << t1 << " " << t2 << std::endl; > bar(ts...); > } > }; It should be possible, but not as you tried. The reason of failure is simple due to the fact that once Foo has been instantiated you have selected a variadic of given sice. To fix this, just make bar a function template that is constrained regarding the number of arguments. Your can also add type-matching requirements via sfinae combinaed with std::is_same or std::is_convertible, but I omitted that in the following: template <typename Type, typename ... Types> struct Foo { void bar(Type t1, Type t2) { std::cout << t1 << " " << t2 << std::endl; } template<typename... U, typename = typename std::enable_if<sizeof...(U) == 2*sizeof... (Types)>::type> void bar(Type t1, Type t2, U... ts) { std::cout << t1 << " " << t2 << std::endl; bar(ts...); } }; Whether this works, depends on your Type/Types combinations. Then pack expansion inside bar will try to match the first two members of ts with Type, so this will only work, if each Ui in U satisfies the constraint std::is_same<Ui, Type> or std::is_convertible<Ui, Type>. You can add this as one sfinae blocker in the dummy type added to bar's template parameter list. HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: PGK on 8 Mar 2010 02:15 On 8 Mar, 09:03, Daniel Kr�gler <daniel.krueg...(a)googlemail.com> wrote: > On 8 Mrz., 02:33, PGK <graham.k...(a)gmail.com> wrote: > > > I'd like to define a method which takes twice (say) the number of > > template parameters which define the class. The following class > > attempts to use explicit recursion for this, but fails. Does anyone > > know if this is possible? > > > template <typename Type, typename ... Types> > > struct Foo { > > void bar(Type t1, Type t2) { std::cout << t1 << " " << t2 << > > std::endl; } > > void bar(Type t1, Type t2, Types ... ts) { > > std::cout << t1 << " " << t2 << std::endl; > > bar(ts...); > > } > > }; > > It should be possible, but not as you tried. The reason of failure > is simple due to the fact that once Foo has been instantiated > you have selected a variadic of given sice. To fix this, just > make bar a function template that is constrained regarding > the number of arguments. Your can also add type-matching > requirements via sfinae combinaed with std::is_same or > std::is_convertible, but I omitted that in the following: > > template <typename Type, typename ... Types> > struct Foo { > void bar(Type t1, Type t2) { std::cout << t1 << " " << t2 << > std::endl; } > template<typename... U, > typename = typename std::enable_if<sizeof...(U) == 2*sizeof... > (Types)>::type> > void bar(Type t1, Type t2, U... ts) { > std::cout << t1 << " " << t2 << std::endl; > bar(ts...); > } > > }; > > Whether this works, depends on your Type/Types > combinations. Then pack expansion inside bar > will try to match the first two members of ts > with Type, so this will only work, if each Ui in U > satisfies the constraint std::is_same<Ui, Type> > or std::is_convertible<Ui, Type>. > > You can add this as one sfinae blocker in the > dummy type added to bar's template parameter > list. { edits: quoted signature and banner removed. please keep readers in mind when quoting. -mod } Many thanks, this helps a lot. I like the look of this approach, but so far I've had no luck with the class you posted. It will compile when no class is instantiated, but if I declare: Foo<char,int,double> X; within a minimal "main", I get the error: var.cpp:40: error: no type named 'type' in 'struct std::enable_if<false, void>' Perhaps it's my compiler (gcc 4.3.2); I have 4.4 at home. One thing I find surprising is that I had thought that a template parameter pack must be the last entry in a template parameter list. All the best, Graham -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Daniel Krügler on 8 Mar 2010 05:01 On 8 Mrz., 20:15, PGK <graham.k...(a)gmail.com> wrote: > On 8 Mar, 09:03, Daniel Kr�gler <daniel.krueg...(a)googlemail.com> > > Whether this works, depends on your Type/Types > > combinations. Then pack expansion inside bar > > will try to match the first two members of ts > > with Type, so this will only work, if each Ui in U > > satisfies the constraint std::is_same<Ui, Type> > > or std::is_convertible<Ui, Type>. > > > You can add this as one sfinae blocker in the > > dummy type added to bar's template parameter > > list. [..] > Many thanks, this helps a lot. I like the look of this approach, but > so far > I've had no luck with the class you posted. It will compile when no > class is > instantiated, but if I declare: > Foo<char,int,double> X; > within a minimal "main", I get the error: > var.cpp:40: error: no type named 'type' in 'struct > std::enable_if<false, void>' > > Perhaps it's my compiler (gcc 4.3.2); I have 4.4 at home. This looks like an error in your compiler. Btw.: After you provided your example, I think you need some refactoring. IMO the implementation you want is this one: template <typename Type, typename ... Types> struct Foo { private: template<typename V> void do_bar(V t1, V t2) { std::cout << t1 << " " << t2 << std::endl; } template<typename V, typename... U> void do_bar(V t1, V t2, U... ts) { std::cout << t1 << " " << t2 << std::endl; do_bar(ts...); } public: template<typename... U, typename = typename std::enable_if< sizeof...(U) == 2 * sizeof...(Types)>::type> void bar(Type t1, Type t2, U... ts) { do_bar(t1, t2, ts...); } }; Otherwise the compiler will not find the matching overload with your mixed types. > One thing I find surprising is that I had thought that a template > parameter pack must be the last entry in a template parameter list. This is intended, because function template arguments can be deduced, so their is no need that that the variadic parameters are at the end of the template parameter list. The fascinating result of this is that sinfae of c'tors does no longer require a dummy function parameter. HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: PGK on 16 Mar 2010 14:56
Would there be any disadvantage in using static_assert, instead of the extra sfinae template parameter method you present? For example: template<typename... U> void bar(Type t1, Type t2, U... ts) { static_assert(sizeof...(U) == 2 * sizeof...(Types), "Error"); do_bar<0>(t1, t2, ts...); } -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |