аргументы шаблона во время компиляции развернуты для цикла? - PullRequest
6 голосов
/ 19 июля 2011

Википедия ( здесь ) дает время развертывания цикла 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 . Я еще не реализовал это, но я предполагаю, что это дает способ сделать то, что я хотел .....

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

использование хорошо иллюстрируется на примере

Ответы [ 3 ]

8 голосов
/ 19 июля 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.

2 голосов
/ 19 июля 2011

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

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

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

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

    SubDomain<i> tmp(member);

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

Pedantry

Стандарт присваивает термин 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), как выражения регистра (6.4.2), как длины битового поля (9.6), как инициализаторы перечислителя (7.2), как инициализаторы статических членов (9.4.2), и в качестве целочисленных или перечисляемых нетиповых аргументов шаблонного типа (14.3) .

Тогда ключ:

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

Приложение Pedantry

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

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>();
}

Но если сделать только одну часть цепочки неconst, то 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
}

Сводка

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

  • инициализатор постоянной времени компиляции должен включать только другие постоянные времени компиляции
  • литеральное значение является постоянной времени компиляции
  • значение перечисления является постоянной времени компиляции
  • вызовы функций не дают постоянных времени компиляции (по некоторым сложным причинам)
0 голосов
/ 19 июля 2011

Re-Edit

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

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

...