#c #templates #language-lawyer #crtp
Вопрос:
Этот пример сценария полностью компилируется в gcc 8.2, но в Visual Studio 2019 он возвращается error C3200: 'bar<int>': invalid template argument for template parameter 'bar', expected a class template
в строке, где появляется » новое:
template<typename T, template<typename> class bar>
class foo;
template<typename T>
class bar
{
friend class foo<T, bar>;
};
template<typename T, template<typename> class bar>
class foo
{
};
class baz : bar<int>
{
public:
void mash()
{
auto whoosh = new foo<int, bar>();
}
};
int main(int argc, char **argv)
{
baz A;
A.mash();
return 0;
}
Читая, я думаю, что проблема может заключаться в том, что второй аргумент шаблона в этой строке теперь является четко определенным типом, а не шаблоном, но даже если это правда, я не знаю, что с этим делать. Замена « bar
на « decltype(bar)
ни к чему меня не привела.
Я был бы рад любым предложениям.
Ответ №1:
Я признаю, что не знаю, кто здесь прав или неправ (см. Ниже). Путаница, по-видимому, связана с тем фактом, что внутри шаблона класса baz
, наследуемого от bar<int>
идентификатора bar
, интерпретируется как bar<int>
. Странно bar
само по себе использование bar
ссылки на шаблон не позволяет bar<T>
. И составители с этим не согласны. В любом случае, все компиляторы, которые вы включили в представление соответствия, примут код, если вы измените его на:
class baz : bar<int>
{
public:
void mash()
{
auto whoosh = new foo<int, ::bar>();
}
};
Как отметил Джарод 42:
Из введенного имени класса#In_class_template: «В следующих случаях введенное имя класса обрабатывается как шаблон-имя самого шаблона класса:-оно используется в качестве аргумента шаблона, соответствующего параметру шаблона шаблона». итак, ошибка msvc.
И, благодаря ашеплеру за ссылку, официальную формулировку стандарта можно найти в [temp.local] в пункте 1.
Так что того, что я назвал «странным» выше, следует ожидать. Например:
template <typename T>
struct moo {
moo some_method();
//^ refers to moo<T>
foo<int,moo> some_other_method();
// ^ refers to moo
};
И то, с чем вы столкнулись, — это случай, когда msvc неправильно реализует это исключение.
Комментарии:
1. Из введенного имени класса#In_class_template : «В следующих случаях введенное имя класса обрабатывается как шаблон-имя самого шаблона класса:-оно используется в качестве аргумента шаблона, соответствующего параметру шаблона шаблона» . итак, ошибка msvc.
2. Да, спасибо, это ключ к разгадке. В мой фактический код, с ‘foo’, ‘bar’ и ‘база’ в пространстве имен, так что я должен сделать, это поставить явного пространства имен классификатор напротив «панели», я.Е «авто-ш-ш-ш = новый foo в<int, ns::bar=»»>();», но затем он компилирует это работает хорошо.
3. Я подумал, что, возможно, это простой вопрос двусмысленности, с одним и тем же символом, используемым как для параметра шаблона, так и для конкретного класса: но я попытался заменить «панель классов шаблона<имя_типа>» на «шаблон<имя_типа><имя_типа> класса U» в объявлении и определении «foo», и это не имело никакого значения.
4. @EosPengwern не в этом проблема, имя аргумента не имеет значения за пределами шаблона.
5. Также в самом стандарте см. [temp.local] , пункт 1.