Как оказать поддержку конструктору шаблонного класса?

Почему делает

class A;
template<typename T> class B
{
private: 
    A* a;

public:  
    B();
};


class A : public B<int>
{
private:    
    friend B<int>::B<int>();
    int x;
};


template<typename T>
B<T>::B()
{
    a = new A;
    a->x = 5;
}

int main() { return 0; }

результат в

../src/main.cpp:15: ошибка: недопустимое использование конструктора как шаблон
../src/main.cpp:15:примечание: используйте ‘B:: B’ вместо ‘B:: класс B’ для именования конструктора на полностью определенное имя

все же изменение friend B<int>::B<int>() кому: friend B<int>::B() результаты в

../src/main.cpp:15: ошибка: никакой ‘пустой B:: B ()’ функция членства объявляется в классе 'B'

при удалении шаблона полностью

class A;
class B
{
private:
    A* a;

public:
    B();
};


class A : public B
{
private:
    friend B::B();
    int x;
};


B::B()
{
    a = new A;
    a->x = 5;
}

int main() { return 0; }

компиляции и выполняются очень хорошо - несмотря на моего друга высказывания IDE B:: B () недопустимый синтаксис?

6
задан Kyle 12 May 2010 в 23:25
поделиться

4 ответа

Согласно разрешению дефекта CWG 147 (разрешение было включено в C ++ 03), правильный способ назвать нешаблон Конструктор специализации шаблона класса:

B<int>::B();

, а не

B<int>::B<int>();

Если бы последнее было разрешено, возникла бы двусмысленность, когда у вас есть специализация шаблона конструктора для специализации шаблона класса: будет ли второй быть для шаблона класса или шаблона конструктора? (см. отчет о дефектах, ссылка на который приведена выше, для получения дополнительной информации об этом)

Итак, правильный способ объявить конструктор специализации шаблона класса в качестве друга:

friend B<int>::B();

Comeau 4.3.10.1 и Intel C ++ 11.1 принимают эту форму . Ни Visual C ++ 2008, ни Visual C ++ 2010 не принимают эту форму, но оба принимают (неправильную) форму friend B :: B (); (Я отправлю отчет о дефекте в Microsoft Connect ).

gcc не принимает ни одну из форм до версии 4.5. Ошибка 5023 была обнаружена в gcc 3.0.2, но запрошенное решение в отчете об ошибке было неправильной формой. Похоже, что исправление ошибки 9050 также решает эту проблему, и gcc 4.5 принимает правильную форму. Георг Фриче подтвердил это в комментарии к вопросу.

5
ответ дан 17 December 2019 в 00:05
поделиться

И почему ваша IDE показывает другу B :: B () как недопустимый синтаксис в последнем случае? Ошибка IDE.

Обходной путь, который я нашел в gcc для случая шаблона, если вы не можете обновить, - это переместить реализацию B () в функцию-член void B :: init () и вместо этого предоставить ей дружбу. Готов поспорить, это тоже закроет вашу IDE.

Даже если вы получите это для компиляции, вы столкнетесь с проблемой переполнения стека, как только попытаетесь создать экземпляр B.

1
ответ дан 17 December 2019 в 00:05
поделиться

Не помогает определение типа? например

class A : public B<int>
{
    typedef B<int> Base;   
    friend Base::Base();
    int x;
};

РЕДАКТИРОВАТЬ: Окончательный проект комитета для C ++ 0x включает следующий язык в раздел 3.4.3.1 [ class.qual ]:

При поиске, в котором конструктор является приемлемым результатом поиска а спецификатор вложенного имени назначает класс C : если имя указано после спецификатора вложенного имени , при поиске в C , это имя внедренного класса C (пункт 9), или если имя, указанное после спецификатора вложенного имени , совпадает с идентификатор или идентификатор простого-шаблона имя-шаблона в последнем компоненте спецификатора вложенного имени , вместо этого используется имя считается конструктором класса C .

Похоже, что имя ( Base ), указанное после описателя вложенного имени ( Base :: ), совпадает с идентификатором в последнем компоненте спецификатора вложенного имени , поэтому этот код действительно называет конструктор.

Но я не могу согласовать это с разделом 12.1 [ class.ctor ]:

Поскольку у конструкторов нет имен, они никогда не обнаруживаются при поиске имени

Да правда? Как этот язык в 3.4.3.1 снова работает?

typedef-name не должен использоваться в качестве class-name в declarator-id для объявление конструктора.

Это кажется довольно ясным, за исключением раздела 12.1, кажется, обсуждает только вводное объявление конструктора, поскольку параграф 1 исключает спецификатор вложенного имени , friend и с использованием . Если это применимо к объявлениям друзей, это также, похоже, запрещает friend Base :: B ();

Специальный синтаксис декларатора с использованием необязательной последовательности спецификаторов функций (7.1.2) за которым следует имя класса конструктора, за которым следует список параметров, который используется для объявления или определения конструктора.

Эти спецификаторы функций являются встроенными , виртуальными , явными , а конструкторы не могут быть виртуальными ] в любом случае.

1
ответ дан 17 December 2019 в 00:05
поделиться

Я думаю, что вы далеко зашли на территорию причуд с шаблонированными конструкторами друзей. Это компилируется и работает нормально на VS2010, но это приводит к переполнению стека, когда конструктор по умолчанию A вызывает конструктор по умолчанию B, который затем снова инстанцирует A.

0
ответ дан 17 December 2019 в 00:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: