Метод шаблона и аргумент шаблона по умолчанию
Моя проблема может быть возобновлена с помощью следующего кода:
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++, только для того же кода, компилируется нормально!
Мои вопросы:
- Какой компилятор имеет правду?
- Есть ли альтернатива для выражения того же смысла с текущей версией компилятора 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.