Clang и Intel не могут скомпилировать этот код CRTP

Я написал небольшую библиотеку, в которой используется множество методов метапрограммирования C ++ 11 и CRTP, и она хорошо компилируется с g ++ 4.7.2

Теперь я пытаюсь скомпилировать его с Intel ICPC 13.0.0.079, и он генерирует несколько сотен ошибок. Поэтому я стараюсь выявлять проблемы одну за другой.

Итак, во-первых, рассмотрим этот код, который без проблем компилируется под g ++ 4.7.2

#include <iostream>

template<template<typename> class Crtp, typename Type>
struct Base {};

template<typename Type>
struct Derived : public Base<Derived, Type>
{
Derived(): Base<Derived, Type>() {;}
};

int main()
{
Derived<int> x;
return 0;
}

И icpc, и clang не могут скомпилировать этот код:

test_crtp.cpp(26): error: type "Derived<Type>::Derived" is not a class template
Derived(): Base<Derived, Type>() {;}
^

test_crtp.cpp(26): error: "Base" is not a nonstatic data member or base class of class "Derived<int>"Derived(): Base<Derived, Type>() {;}
^
detected during instantiation of "Derived<Type>::Derived() [with Type=int]" at line 31

compilation aborted for test_crtp.cpp (code 2)

Так это ошибка в intel и clang или в g ++? Если это в intel и clang, думаете ли вы, что это будет решено в будущей версии?

11

Решение

Внутри класса Derived, имя Derived ссылается на (созданный экземпляр) класс, а не на шаблон класса. Пытаться Base< ::Derived, Type> вместо этого (будьте осторожны, чтобы оставить пространство между < а также ::).

7

Другие решения

В разделе 9.2.3 Шаблон C ++ Полное руководство (Амазонка), есть обсуждение Имен введенных классов. Цитировать:

Шаблоны классов также имеют введенные имена классов. Тем не менее, они
незнакомые, чем обычные введенные имена классов: за ними могут следовать
аргументы шаблона (в этом случае в них вводится шаблон класса
имена), но если они не сопровождаются аргументами шаблона, они
представлять класс с его параметрами в качестве аргументов (или, для
частичная специализация, аргументы ее специализации). Это объясняет
следующая ситуация:

template<template<typename> class TT>
class X {};

template<typename T>
class C
{
Ca;        // OK: same as ''C<T> a;''
C<void> b; // OK
X<C> c;    // ERROR: C without a template argument list
// does not denote a template
X<::C> d;  // ERROR: <: is an alternative token for [
X< ::C> e; // OK: the space between < and :: is required
}

Обратите внимание, что неквалифицированное имя относится к введенному имени и не является
считается имя шаблона, если за ним не следует список
аргументы шаблона. Чтобы компенсировать это, мы можем заставить имя
шаблон можно найти с помощью спецификатора области файла ::. Это работает,
но мы должны быть осторожны, чтобы не создавать так называемый орграф
<:, который интерпретируется как левая скобка. Хотя относительно редко,
такие ошибки приводят к сбивающей с толку диагностике.

Итак, что происходит в вашем коде, так это Base<Derived, Type> интерпретируется как Base<Derived<Type>, Type> который плохо сформирован. Поэтому вам нужно использовать квалификатор области :: с пробелом между < избегать орграфа.

6

По вопросам рекламы [email protected]