Метод шаблона и аргумент шаблона по умолчанию

Моя проблема может быть возобновлена ​​с помощью следующего кода:

template <typename T> struct C2;

template <typename T> 
struct C1
{
  template <typename Type,
        template <typename Ti> class Container = C2>
  void m() {}
};


template <typename T> 
struct C2
{
  template <typename Type = int,
        template <typename Ti> class Container = C2> // <-- Here is the problem!
  void m() {}

};

Компилятор gnu версии 4.8.1 завершается ошибкой со следующим сообщением:

test-temp.C:16:47: error: invalid use of type ‘C2<T>’ as a default value for a template template-parameter
      template <typename Ti> class Container = C2> 

Это относится к параметру шаблона C2 по умолчанию для метода C2::m.

Видимо (это мое мнение), компилятор видит C2<T> в качестве параметра по умолчанию вместо C2 (без <T>). Таким образом, когда он находит инструкцию, он терпит неудачу, потому что тип C2<T> не совпадает с Container,

Тем не менее, Clang++, только для того же кода, компилируется нормально!

Мои вопросы:

  1. Какой компилятор имеет правду?
  2. Есть ли альтернатива для выражения того же смысла с текущей версией компилятора gnu?

заранее спасибо

Leandro

2 ответа

Решение

Я думаю, что Clang верен, а g++ ошибочен, цитирую черновик стандарта (жирный шрифт - мой)

14.6.1 Локально объявленные имена [temp.local]

1 Как и обычные (не шаблонные) классы, шаблоны классов имеют имя введенного класса (раздел 9). Имя injectedclass-name может использоваться в качестве имени шаблона или имени типа. Когда он используется со списком аргументов шаблона, в качестве аргумента шаблона для параметра шаблона или в качестве окончательного идентификатора в подробном спецификаторе типа объявления шаблона класса друга, он ссылается на сам шаблон класса. В противном случае оно эквивалентно имени шаблона, за которым следуют параметры шаблона шаблона класса, заключенного в <>.

Вы можете использовать :: оператор разрешения области действия, чтобы превзойти g++ в представлении

template <typename T> 
struct C2
{
  template <typename Type = int,
        template <typename Ti> class Container = ::C2> 
                                              // ^^ <-- here is the solution!
  void m() {}

};

Живой пример.

Значит, ссылка 14.6.1 в ответе TemplateRex означает, что G++ правильный (а Clang и VC++ неправильные), чтобы принять это, поскольку он использует X в качестве аргумента шаблона для параметра шаблона шаблона?

template< template< typename > class T >
class factory { };

template< typename T >
class X
{
      friend class factory< X >;  // ***
};

int main()
{
}

В этом примере G++ рассматривает X как имя шаблона класса, тогда как Clang и VC++ рассматривают его как имя внедренного класса.

Изменить: Clang 5.0.0 теперь принимает код, так же, как G++ и EDG.

Другие вопросы по тегам