аргументы шаблона во время компиляции развернуты для цикла?

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

следующий цикл действителен

template<int max_subdomain>
void Device<max_sudomain>::createSubDomains()
{
    for(int i=0; i< max_subdomain; ++i)
    {
        SubDomain<i> tmp(member);
        ...
        // some operations on tmp
        ...
    }
}

SubDomain — это класс, который принимает параметр шаблона int и здесь был построен с аргументом, который является членом класса Device.

Спасибо за ответ, ребята... теперь, когда вы знаете, чего я хочу... могу ли я добиться того, чего хочу??

наконец-то я получил то, что хотел............. вместо того, чтобы использовать цикл for напрямую... вместо этого можно использовать конструкция Boost::MPL for_each. Я еще не реализовал это, но я предполагаю, что это дает возможность делать то, что я хотел.....

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

использование хорошо показано в пример


person Community    schedule 19.07.2011    source источник
comment
Ты это пробовал? Что вы подразумеваете под действительным? В чем вопрос?   -  person Luc Danton    schedule 19.07.2011
comment
ну на самом деле... в моем коде сейчас все тихо и беспорядочно...   -  person    schedule 19.07.2011
comment
@Jayesh, пожалуйста, обратитесь к отредактированному ответу. Я допустил ошибку в демо-коде.   -  person iammilind    schedule 19.07.2011
comment
Комментарий о его использовании относится к 2D-циклу, который на самом деле не требует развертывания во время компиляции. Если вам нужно SubDomain<i> для всех значений <i>, то, естественно, компилятор должен создать их все экземпляры. Это неизбежная работа.   -  person MSalters    schedule 19.07.2011
comment
@MSalters: спасибо за разъяснение ...........   -  person    schedule 19.07.2011


Ответы (3)


Редактировать повторно:

Мой предыдущий ответ был правильным. Я попробовал ваш код, он выдает ошибку компиляции. Вы не можете объявлять такие объекты, так как i не может оставаться константой времени компиляции (как вы собираетесь сделать i++). Параметр template всегда должен быть константой времени компиляции. Вот демонстрация.

Также обратите внимание, что развертывание цикла выполняется и для обычных циклов, как часть оптимизации компиляторами. Это не ограничивается templates.

person iammilind    schedule 19.07.2011
comment
вы, вероятно, поняли это с первого раза ... Ваша демонстрация не такая, как пример, который дает @Jayesh. В вашем коде вы создаете экземпляр A с N, который действительно является константой времени компиляции. В примере OP он пытается создать экземпляр шаблона, используя i, что является обычной переменной. Это не может работать, потому что компилятор не может создавать экземпляры классов неизвестного типа во время компиляции. Таким образом, код OP недействителен и не будет компилироваться. - person eran; 19.07.2011
comment
@eran, спасибо, что указали на ошибку. Я повторно изменил ответ обратно. - person iammilind; 19.07.2011
comment
спасибо.... на самом деле я не пытался использовать его прямо сейчас, но сейчас я это сделал... и это тоже выдало мне ошибку.... - person ; 19.07.2011
comment
пожалуйста, обратитесь к последней строке моего отредактированного вопроса.... можно ли как-то достичь того, чего я хочу, без использования динамического полиморфизма? все известно во время компиляции... но не известно при написании кода.... - person ; 19.07.2011
comment
@Jayesh, к сожалению, есть способ. Потому что max_subdomain может быть любой константой, и мы не можем объявить объект на ее основе. Но если вы можете описать каковы были ваши цели при объявлении таких объектов в новом вопросе, вы можете получить хорошую помощь в поиске лучшего способа. - person iammilind; 19.07.2011
comment
ох...... я напишу новый вопрос...... я довольно плохо разбираюсь в коммуникациях.... будем надеяться, что на этот раз я сделаю это правильно........ - person ; 19.07.2011
comment
я думаю, что нашел ответ на вопрос... но по-другому..... используя конструкцию for_each из Boost MPL - person ; 19.07.2011
comment
-1: as soon as you do i++ i cannot remain a compile time constant -> i никогда не было константой времени компиляции. Она была объявлена ​​как изменяемая переменная, и поэтому она не может остаться константой времени компиляции, потому что она никогда не была - person Sebastian Mach; 19.07.2011
comment
@phresnel, ты ошибаешься. Объявление i как const int действительно делает время компиляции постоянным. см. здесь: ideone.com/Tjgsn. Но тогда вы не можете сделать i++. Я написал это намеренно о философии вопроса. - person iammilind; 19.07.2011
comment
@iammilind: Чтение вашего ответа как есть говорит мне, что ++ устраняет время компиляции некоторой переменной. Но это не так. Декларация может сделать это. И этим нет, я не ошибаюсь, но спасибо за попытку научить меня. И, кстати, простое объявление чего-либо как const не обязательно делает время компиляции постоянным. См. эту демонстрацию. - person Sebastian Mach; 19.07.2011
comment
@phresnel, ваш пример в другом контексте. В цикле for OP инициализировался литералом 0. Если вы неправильно поняли ответ, это зависит от вас. - person iammilind; 19.07.2011
comment
@iammilind: Почему важно, было ли i объявлено в инициализаторе цикла for или нет? Если вы посмотрите на стандарт, вы обнаружите, что инициализатором цикла for является либо expression-statement, либо simple-declaration, поэтому int i в инициализаторе цикла for эквивалентно тому, которого нет в инициализаторе цикла for. Попробуй сначала сделать домашнее задание, пожалуйста. - person Sebastian Mach; 19.07.2011
comment
@iammilind: Если это не то, что вы намеревались задать, может быть, это: OP объявил счетчик циклов точно как int i=0. Я тоже в своем связанном примере. И OP, и ME не сделали его const, поэтому он не является константой времени компиляции. Чтобы сделать целое число постоянным во времени компиляции, вы должны использовать const или в C++0x constexpr, и вы должны инициализировать его литеральным значением и/или другим выражением, постоянным во времени компиляции. См. эту демонстрацию, которая написана на правильном языке C++. - person Sebastian Mach; 19.07.2011
comment
спасибо, ребята...... @iammilind: спасибо.... особенно за все примеры, которые вы написали для иллюстрации.. спасибо..... - person ; 19.07.2011

Для этого есть стандартное решение. Преобразовать итерацию в рекурсию.

template<int i>
void Device::createSubDomains()
{
    SubDomain<i> tmp(member);
    // some operations on tmp
    createSubDomains<i-1>();
}
template<>
void Device<-1>::createSubDomains()
{
  // End of recursion.
}

Примечание: вы не можете использовать среду выполнения if(i!=0) createSubDomains<i-1>();.

2017 Примечание: теперь вы можете использовать время компиляции if constexpr(i!=0) createSubDomains<i-1>();

person MSalters    schedule 19.07.2011
comment
да.. я знал об этом... это тоже работает..... но когда я увидел пример цикла for в вики, просто должен был спросить........ все равно спасибо за ответ... если я буду использовать это или нет, зависит от некоторых других реализаций в классе... мне нужно попробовать и посмотреть... дам вам знать, какой я выберу и почему... - person ; 19.07.2011

Несмотря на то, что вы уже приняли ответ @iammilind, позвольте мне предложить еще один, потому что его рассуждения о том, почему i не является константой времени компиляции is, были неверными.

Предположим, у вас есть

    template<unsigned int MAX> struct SubDomain {...};
    ...

и вы хотите объявить его экземпляр...

    SubDomain<i> tmp(member);

тогда i должно быть так называемой константой времени компиляции. Что это?


Педантичность

Стандарт присваивает термин nontype template argument аргументам шаблона, которые не являются типами (D'Oh).

14.3.2 Шаблоны нетиповых аргументов [temp.arg.nontype]

Аргумент-шаблон для нетипового, нешаблонного параметра-шаблона должен быть одним из:
— интегральная константа-выражение интегрального или перечисляемого типа; или
— ... [дальше следуют, но не актуальны]

Справа первый пункт содержит ссылку для дальнейшего исследования: an integral constant-expression. Это приводит нас к

5.19 Константные выражения [expr.const]

В некоторых местах C++ требует выражений, которые возвращают интеграл или константу перечисления: в качестве границ массива (8.3.4, 5.3.4), в качестве выражения case (6.4.2), в качестве длины битового поля (9.6), в качестве инициализаторы перечислителя (7.2), как инициализаторы статических членов (9.4.2), и как целочисленные или перечисляемые аргументы нетипового шаблона (14.3).

Тогда ключ:

Интегральное выражение-константа может включать только литералы (2.13), перечислители, константные переменные или статические элементы данных целочисленного или перечисляемого типов, инициализированные константными выражениями (8.5), нетиповые параметры шаблона целочисленного или перечисляемого типов и выражения sizeof.


Применение педантизма

Если мы оглянемся на ваш цикл:

for (int i=...
    ...
    SubDomain<i>

то теперь мы можем заметить, что i там не разрешено. Почему? Потому что i НЕ const variable.

Наблюдательный читатель может теперь подумать, что вы можете обойти это:

for (int i=...
        ...
        const int I = i;
        SubDomain<I>

Но действительно ли это разрешено? Отрицательное значение, I = i не является интегральным константным выражением, потому что i таковым не является. Это помогает понять, что правило для целочисленных константных выражений применяется рекурсивно.

Например, следующий код является допустимым:

template <int> void foo() {}     
int main () {
    const int ccI = 0;
    const int ccJ = ccI*2;
    const int ccK = ccJ/4;     
    foo<ccK>();
}

Но если хотя бы одну часть цепочки сделать непостоянной, то ccK уже не считается интегральной константой:

template <int> void foo() {}     
int main () {
          int ccI = 0;
    const int ccJ = ccI*2;  // not compile time constant
    const int ccK = ccJ/4;  // same

    foo<ccK>();             // error
}


Резюме

Итак, в удобочитаемой форме аргументы шаблона, которые не являются типами, а (целочисленными) значениями, должны быть постоянными во время компиляции:

  • инициализатор константы времени компиляции должен включать только другие константы времени компиляции
  • буквальное значение является константой времени компиляции
  • значение перечисления является константой времени компиляции
  • функциональные вызовы не дают констант времени компиляции (по некоторым дополнительным причинам)
person Sebastian Mach    schedule 19.07.2011