Bug 35722 - [C++0x] Variadic templates expansion into non-variadic class template
Summary: [C++0x] Variadic templates expansion into non-variadic class template
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.4.0
: P3 normal
Target Milestone: 4.7.0
Assignee: Jason Merrill
URL:
Keywords: rejects-valid
: 39642 45873 50140 (view as bug list)
Depends on:
Blocks: 39653
  Show dependency treegraph
 
Reported: 2008-03-27 17:31 UTC by dgregor
Modified: 2012-06-08 08:44 UTC (History)
11 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2008-03-27 17:31:52


Attachments
tuple & union examples with possibly proper variadic return type case relying on variadic template expansion (618 bytes, text/plain)
2009-08-13 05:01 UTC, jack.q.word
Details

Note You need to log in before you can comment on or make changes to this bug.
Description dgregor 2008-03-27 17:31:36 UTC
The following well-formed example produces the incorrect error:
  
  error: cannot expand ‘G ...’ into a fixed-length argument list

template<typename G = void, typename H = void>
struct foo
{};

template<typename... G>
struct bar : foo<G...>
{};

int main() {
  bar<int, float> f;
}
Comment 1 Jason Merrill 2009-01-06 19:47:07 UTC
This was ill-formed under the proposal that was initially adopted, but was made well-formed in the March 2008 working paper when the following wording was struck from the end of 14.3:

A template-argument pack expansion shall not occur in a simple-template-id whose template-name refers to a class template unless the template-parameter-list of that class template declares a template parameter pack.
Comment 2 Jason Merrill 2009-01-07 00:06:03 UTC
This was part of the incorporation of N2555 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf) into the WP.
Comment 3 Martin Sebor 2009-04-04 23:12:44 UTC
This limitation makes implementing the latest std::tuple difficult. Quoting
from a post to c++std-lib@accu.org:

Martin Sebor wrote:
> To: C++ libraries mailing list
> Message c++std-lib-23549
> 
> After reducing the error to a smaller test case and some digging
> through gcc Bugzilla it looks as though it is well-formed but gcc
> doesn't implement it yet:
> 
>   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35722
> 
> The errors are different but the problem seems the same in both
> cases.
> 
> Martin Sebor wrote:
>> To: C++ libraries mailing list
>> Message c++std-lib-23548
>>
>> I'm probably missing something but can someone confirm that the
>> declaration of the tuple ctor below (taken from N2857) is well
>> formed given that pair is not a variadic template?
>>
>> The latest gcc complains:
>>
>>   error: wrong number of template arguments (1, should be 2)
>>
>> Thanks!
>>
>>   template <VariableType... Types>
>>   class tuple
>>   {
>>   public:
>>     ...
>>     template <Allocator Alloc, class... UTypes>
>>     requires ConstructibleWithAllocator<Types, Alloc, const UTypes&>...
>>     tuple(allocator_arg_t, const Alloc& a, const pair<UTypes...>&);
>>     ...
>>   };
>>
>>
>> Here's a small test case:
>>
>> $ cat t.C && g++ -std=c++0x t.C
>> template <class T, class U> struct pair { };
>> struct allocator_arg_t { };
>> template <class ...T>
>> struct tuple {
>>     template <class U, class ...V>
>>     tuple (allocator_arg_t, const U&, const pair<V...>&);
>> };
>> t.C:6: error: wrong number of template arguments (1, should be 2)
>> t.C:1: error: provided for ‘template<class T, class U> struct pair’
Comment 4 Jason Merrill 2009-04-05 04:20:12 UTC
I agree that the working paper says that this should work, but I'm not sure why the language should specify the use of variadics there; why not

     template <Allocator Alloc, class First, class Second>
     requires ConstructibleWithAllocator<Types, Alloc, const First&>
       && ConstructibleWithAllocator<Types, Alloc, const Second&>
     tuple(allocator_arg_t, const Alloc& a, const pair<First, Second>&);

instead?  The n2555 fix is needed for template template parameters, but in cases like this where we know what template we're dealing with I don't see why it's a problem to just pass in the right number of arguments.
Comment 5 Martin Sebor 2009-04-05 14:20:31 UTC
(In reply to comment #4)

The change was introduced in N2622:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2622.pdf

I couldn't find a rationale for the change. Doug might remember
Comment 6 Martin Sebor 2009-04-05 17:12:33 UTC
See also bug 39642 and bug 39653.
Comment 7 Jason Merrill 2009-04-05 19:33:42 UTC
*** Bug 39642 has been marked as a duplicate of this bug. ***
Comment 8 jack.q.word 2009-08-13 05:01:22 UTC
Created attachment 18348 [details]
tuple & union examples with possibly proper variadic return type case relying on variadic template expansion
Comment 9 jack.q.word 2009-08-13 05:04:37 UTC
(In reply to comment #8)
> Created an attachment (id=18348) [edit]
> tuple & union examples with possibly proper variadic return type case relying
> on variadic template expansion
> 

the unnamed structs/unions, and RecursiveStruct/Union can be discarded, and use 'byte Data[VarTypeNav< cT, vT...>::Size];' ...
Comment 10 jack.q.word 2009-08-13 05:05:55 UTC
> 'byte Data[VarTypeNav< cT, vT...>::Size];' ...

or 'char Data[VarTypeNav< cT, vT...>::Size];' ...
Comment 11 jack.q.word 2009-08-13 05:14:18 UTC
Comment on attachment 18348 [details]
tuple & union examples with possibly proper variadic return type case relying on variadic template expansion

template< class cT, class... vT >
struct VarTypeNav
{
	typedef cT T;
	typedef VarTypeNav< vT..., void > Next;
	struct scT { cT v; };
	static const size_t Size =
		sizeof(scT) + Next::Size;
	static const size_t Count =
		1 + Next::Count;
};

template< class... vT >
struct VarTypeNav< void, vT... >
{
	typedef void T; 
	typedef void Next;
	static const size_t Size = 0;
	static const size_t Count = 0;
};

template< const size_t nIndex, class cT, class... vT >
struct VarTypeSelect
{
	typedef VarTypeSelect< nIndex-1, vT... >::T T;
	struct scT { T v; };
	static const size_t Offset =
		sizeof(scT) + VarTypeSelect< nIndex-1, vT... >::Offset;
};

template< class cT, class... vT >
struct VarTypeSelect< 0, cT, vT... >
{
	typedef cT T;
	static const size_t Offset = 0;
};

template< class cT, class... vT >
struct Tuple
{
	char Data[VarTypeNav<cT,vT...>::Size];
	template< const size_t index >
	VarTypeSelect< index, vT... >::T & operator [] ( const size_t index )
	{
		static_assert(!(index > VarTypeNav< vT... >::Count ), "Index out of bounds");
		char * pThisChars = (char *) this;
		return *(
			(VarTypeSelect< index, vT... >::T *)
				pThisChars[ VarTypeSelect< index, vT... >::Offset ]));
	}
	template< const size_t index >
	const VarTypeSelect< index, vT... >::T & operator [] ( const size_t index ) const
	{
		static_assert(!(index > VarTypeNav< vT... >::Count ), "Index out of bounds");
		const char * pThisChars = (const char *) this;
		return *(
			(const VarTypeSelect< index, vT... >::T *)
				pThisChars[ VarTypeSelect< index, vT... >::Offset ]));
	}
};

int main() {
	Tuple< size_t, char * > x; /* = { 32, new char[32] }; *//* ? */
	x[0] = 32;
	x[1] = new char[32];
	x[1][31] = 0;
	return (int) &x[1][0] != 0;
}
Comment 12 Chris Jefferson 2010-01-22 09:11:54 UTC
Just for anyone who comes to this bug, it can be worked around by doing something like:

template<template <typename...> T, typename... Args>
struct Join
{ typedef T<Args...> type; }

Although of course that isn't a fix (and unfortunately a fix is beyond me).
Comment 13 Ed Smith-Rowland 2011-05-20 16:55:48 UTC
I this supposed to work too?

//  This is going to be a variadic array.
#include <cstddef>
#include <type_traits>

template<typename T, std::size_t Dim, std::size_t... Dims>
  struct tensor
  {
  public:
    typedef std::conditional<sizeof...(Dims) == 0, T, tensor<T, Dims...>> _Elem;
    _Elem elem[Dim]; // (Dim == 0 ? 1 : Dim) like array?
  };
Comment 14 Tristan Wibberley 2011-05-20 19:30:15 UTC
Ed,

It depends on the rest of your program that you cut out. As given, no it's
not supposed to work.

see http://gcc.gnu.org/bugs/ for how to report your problem if you have a
good reason to think there's a bug. But for help with c++ you need to go
elsewhere for example the ##c++ chatroom on IRC chat as detailed at
http://freenode.net/
Comment 15 Dodji Seketeli 2011-09-27 14:46:22 UTC
Unassigning myself as I am not working on this right now.
Comment 16 Jason Merrill 2011-10-02 21:45:08 UTC
Author: jason
Date: Sun Oct  2 21:45:01 2011
New Revision: 179436

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=179436
Log:
	PR c++/35722
	Implement N2555 (expanding pack expansion to fixed parm list)
	* pt.c (coerce_template_parms): Allow expanding a pack expansion
	to a fixed-length argument list.
	(unify_pack_expansion): Handle explicit args properly.
	(unify) [TREE_VEC]: Handle pack expansions here.
	[TYPE_ARGUMENT_PACK]: Not here.
	(tsubst_pack_expansion): Don't try to do partial substitution.
	(pack_deducible_p): New.
	(fn_type_unification): Use it.
	(find_parameter_packs_r): Take the TYPE_MAIN_VARIANT
	of a type parameter.
	(check_non_deducible_conversion): Split from type_unification_real.
	(unify_one_argument): Split from type_unification_real...
	(unify_pack_expansion): ...and here.  Drop call_args_p parm.
	(type_unification_real, unify, more_specialized_fn): Adjust.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/variadic-explicit1.C
    trunk/gcc/testsuite/g++.dg/cpp0x/variadic-nondeduce1.C
    trunk/gcc/testsuite/g++.dg/cpp0x/variadic117.C
    trunk/gcc/testsuite/g++.dg/cpp0x/variadic118.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/pt.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/g++.dg/cpp0x/variadic105.C
    trunk/gcc/testsuite/g++.dg/cpp0x/variadic35.C
    trunk/gcc/testsuite/g++.dg/cpp0x/variadic65.C
    trunk/gcc/testsuite/g++.dg/cpp0x/variadic82.C
    trunk/gcc/testsuite/g++.dg/cpp0x/variadic83.C
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/testsuite/util/testsuite_tr1.h
Comment 17 Jason Merrill 2011-10-02 21:53:23 UTC
Fixed for 4.7.
Comment 18 Jason Merrill 2011-10-14 19:16:25 UTC
*** Bug 50140 has been marked as a duplicate of this bug. ***
Comment 19 Jason Merrill 2012-04-16 02:10:37 UTC
*** Bug 45873 has been marked as a duplicate of this bug. ***