Вопрос о синтаксисе C ++, включающий нетривиальные шаблоны и объявление друга - PullRequest
3 голосов
/ 31 января 2010

Следующий код не требует пояснений. У меня есть два вопроса относительно используемого синтаксиса (который должен быть использован). Буду вечно благодарен, если вы сможете дать мне ответы на эти вопросы.

template <typename T>
struct A {
    template <typename S>
    void f (const A<S> &s);

    template <typename S>
    friend struct A; 
    // Question 1: why isn't the syntax 'friend struct A<S>' ? 
    // The semantic would stay, since we would like A<S> (for ANY S) to be friend of every A<T>..

    private:
        void g () const {}
};

template <typename T> 
template <typename S> // Question 2: Why can't the syntax be 'template <typename T, typename S>' ?
void A<T>::f (const A<S> &s) {
    s.g();
}

int main () {
    A<bool> abool;
    A<char> achar;

    abool.f(achar);
}

Я подтвердил, что это действительно единственный правильный синтаксис (я буду рад узнать, что я ошибаюсь). Мои вопросы больше касаются обоснования синтаксиса, как объяснено в теле вопроса.

Спасибо за любую помощь.

Ответы [ 3 ]

5 голосов
/ 31 января 2010

Хотя я не могу сказать , почему этот синтаксис был выбран, я могу просто сказать, что буду поддерживать оба решения, принимаемые разработчиками языка - они имеют смысл для меня. В вопросе 2 у вас есть не только один шаблон, у вас есть два вложенных уровня шаблонов. Почему синтаксис для определения элемента шаблона класса шаблона должен скрывать этот факт? Таким образом, это просто повторная комбинация существующего синтаксиса шаблона, в то время как ваш потребует специальных правил для объединения аргументов шаблона для вложенных шаблонов в один template<>.

5 голосов
/ 31 января 2010

почему не синтаксис ...

Почему синтаксис не может быть ...

Что вы ожидаете от нас? Кто бы ни решил этот синтаксис (в основном сам Страуструп, AFAIK), он считал их синтаксис лучше, чем ваш.

Какой из них лучше или легче запомнить, я бы не знал - но я считаю, что их смысл имеет больше смысла, чем ваш. Вы можете не соглашаться, конечно.

Редактировать: ОК, Александр хорошо ответил на вопрос № 2 . О №1:

Разница в том, что A<S> называет тип , что и ожидается для аргумента функции, тогда как A само по себе является именем шаблона от какие типы должны быть созданы, что имеет смысл, если вы хотите подружиться с шаблоном вместо типа:

template <typename S>
void f (const A<S> &s); // A<S> being the name of a type

template <typename S>
friend struct A; // A being the name of a template

Вы можете подружиться с конкретным шаблоном экземпляром вместо всего шаблона, но для этого шаблон должен быть уже известен компилятору (т.е. объявлен) в friend декларация:

template< typename T >
class foo;

class bar {
  friend class foo<int>; // foo<int> being the name of a specific instance of foo
};

Таким образом, поддержка шаблона является исключением ("обычные" friend объявления объявляют функцию или класс) и требуют различного синтаксиса.

2 голосов
/ 31 января 2010

Предположим, ваше объявление вложенного шаблона было немного сложнее:

template <typename T, int I>
struct A {
    template <typename S, I>
    void f (const A<S, I> &s);

    template <typename S, int J>
    friend struct A; 
    // Question 1: why isn't the syntax 'friend struct A<S, J>' ? 
    // The semantic would stay, since we would like A<S, J> (for ANY S, J combination) to be friend of every A<T, I>..

    private:
        void g () const {}
};

template <typename T, int I> 
template <typename S> // Question 2: Why can't the syntax be 'template <typename T, int I, typename S>' ?
void A<T>::f (const A<S> &s) {
    s.g();
}

int main () {
    A<bool, 5> abool;
    A<char, 7> achar;

    abool.f(achar);
}

Внезапно ваше предложение уже не кажется таким разумным или очевидным. Какой набор аргументов идет первым? Предположим, вы использовали C ++ 0x и имели список переменных-переменных?

Что касается объявления друга, имея предлагаемый вами синтаксис (friend struct <S, J>), вы внезапно заставляете компилятор выводить, что S и J подразумеваются как аргументы шаблона и не должны выбираться из некоторого случайного объем. Предположим, кто-то ввел тип S на том же уровне, что и struct A? На какую S будет ссылаться декларация friend struct A<S,J>? Откуда будет знать компилятор? Разумно ли вводить имя во внешнюю область видимости, чтобы радикально изменить значение объявления во вложенной области видимости?

И если вы имели в виду, что объявление должно иметь в итоге: template <typename S, int J> friend struct A<S, J>, то почему объявление переадресации шаблона друга должно выглядеть иначе, чем стандартное объявление шаблона? Излишне включать имена переменных шаблона после имени шаблона, если вы уже упомянули их в части template <typename S, int J>.

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

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

template <typename T>
struct A<T, 5> {
};

И, как вы можете видеть, это странно близко к вашему предлагаемому синтаксису прямого объявления друзей, и может быть трудно определить, намереваетесь ли вы указать специализированную версию или нет. Это потребовало бы сопоставления аргументов шаблона с параметрами шаблона, в то время как в настоящее время, если у вас нет параметров шаблона, вы не говорите о специализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...