Каково различие между C++ 0x понятия и Библиотекой проверки понятия повышения (BCCL)?

Я делаю научные расчеты, где мой GUI находится в C#, и мой бэкенд является C++. Не из области возможности, что C# мог, по крайней мере, равняться C++ с точки зрения производительности, но это не то, где фокус C#/insert управлял языком здесь группы. Это было бы трудно, но хорошо в пределах возможного иметь C# работают, а также C++ (или очень близко к нему) для числового вычисления, поскольку IL компилируется вниз в машинный код. Если/Когда это произойдет, то я с удовольствием переключусь.

19
задан Tobias Furuholm 29 April 2012 в 20:43
поделиться

3 ответа

Проверка определения шаблона

Большое отличие концепций от этих ручных решений состоит в том, что концепции позволяют определять шаблон как проверка типов без каких-либо особых действий. Библиотека проверки концепции позволяет только использовать для проверки типа. Пример:

template<typename InputIterator>
int distance(InputIterator a, InputIterator b) 
{ return b - a; }

Теперь вы можете присыпать этот шаблон проверками концепции и характеристиками, но вы никогда не получите ошибку после написания этого шаблона, потому что Стандарт позволяет компилятору отложить компиляцию шаблона до создания экземпляра. Для проверки необходимо написать классы "архетипа", которые содержат именно те операции, которые требуются интерфейсу, а затем создают их экземпляры искусственно.

Читая документацию по BCCL, я обнаружил, что она уже включает общие архетипы, такие как «конструктивная возможность по умолчанию». Но если вы пишете свои собственные концепции, вам также придется предоставить свои собственные архетипы, что непросто (вы должны найти именно ту минимальную функциональность, которую должен предоставить тип). Например, если ваш архетип содержит оператор - , то проверка вашего шаблона с этим (неправильным) архетипом будет успешной, хотя концепции не требуют такого оператора.

Предложение отклоненных концепций автоматически создает для вас архетипы, на основе заданных и подразумеваемых требований (например, тип указателя T * , используемый в параметре, будет подразумевать требование PointeeType для T ). Вам не нужно заботиться об этом - за исключением, конечно, случаев, когда определение вашего шаблона содержит ошибку типа.

Проверка семантических требований

Рассмотрите этот код, используя гипотетические проверки концепции

template<ForwardIterator I>
void f(I a, I b) {
  // loop two times!
  loopOverAToB(a, b);
  loopOverAToB(a, b);
}

В руководстве BCCL говорится, что семантические требования не проверены. Проверяются только требования синтаксиса и типы. Рассмотрим прямой итератор: существует семантическое требование, чтобы вы могли использовать его в многопроходных алгоритмах. Только проверка синтаксиса не сможет проверить это требование (подумайте, что произойдет, если итератор потока случайно пройдет эту проверку!)

В отклоненном предложении вы должны были явно поставить auto перед определениями концептов, чтобы флаг компилятора успешно прошел проверку синтаксиса. Если auto не был указан, то тип должен был явно определить карту понятий, чтобы сказать, что он поддерживает эту концепцию. Таким образом, итератор потока никогда не будет использоваться для прохождения проверки ForwardIterator.

Переназначение синтаксиса

Это была еще одна особенность. Такой шаблон, как

template<InputIterator I>
  requires OutputStreamable<I::value_type>
void f(I a, I b) {
  while(a != b) std::cout << *a++ << " ";
}

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

f(1, 10);

Это преимущество решения на основе языка, которое, я считаю, не может быть решено BCCL.

Перегрузка на основе концепций

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

template<ForwardIterator I>
I::difference_type distance(I a, I b) {
  I::difference_type d = 0; while(a != b) ++a, ++d;
  return d;
}

template<RandomAccessIterator I>
I::difference_type distance(I a, I b) {
  return b - a;
}

Если тип может использоваться с обоими шаблонами, то будет использоваться второй шаблон, поскольку он более специализирован: RandomAccessIterator уточняет концепцию ForwardIterator .

28
ответ дан 30 November 2019 в 03:43
поделиться

Концептуальная функция C ++ 0x будет функцией основного языка , весь процесс которой будет выполняться компилятором.

Библиотека проверки концепции Boost - это почти такая же функция, но написанная на C ++ и макрос в виде библиотеки для имитации некоторых функций. Он не может делать все, что требуется в окончательной языковой функции (в зависимости от окончательного определения функции), но предоставляет некоторые эквивалентные решения для проверки типа шаблона (и других проверок времени компиляции).

Как было предложено, поскольку концепция C ++ 0x является особенностями языка, она позволит обеспечить более элегантную семантику и позволит компилятору использовать информацию, которая в настоящее время недоступна программе, допуская более подробные или интеллектуальные ошибки во время компиляции (как основная цель концепции - разрешить проверку абстрактного типа в шаблонах).

4
ответ дан 30 November 2019 в 03:43
поделиться

Отказ от ответственности: мне не удалось успешно использовать BCCL в течение последних 30 минут, хотя у меня уже был установлен Boost. Пример, который вы видите ниже, выглядит нормально в соответствии с документацией BCCL для Boost 1.37, но не работает. Я думаю, это считается недостатком.

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

Что касается разрешения перегрузки, вот пример:

template<typename Iter>
void foo(Iter,Iter) {
   BOOST_CONCEPT_ASSERT((RandomAccessIterator<Iter>));
}

void foo(long, int);

int main() {
   foo(2,3); // compile-time error
}

Шаблон подходит лучше, потому что не шаблон требуется преобразование из int в long. Но создание экземпляра не удается, потому что int не является итератором. Вы получаете красивое сообщение об ошибке, объясняющее это, но это не очень приятно, не так ли? С собственными концепциями вы могли бы написать

template<typename Iter>
  requires RandomAccessIterator<Iter>
void foo(Iter,Iter) {}

void foo(long, int);

int main() {
   foo(2,3); // OK, picks non-template foo
}

Здесь шаблон функции не будет участвовать в разрешении перегрузки, потому что требование для T = int не выполняется. Отлично!

Мы все еще можем ограничивать шаблоны функций с помощью трюка SFINAE. C ++ 0x расширяет SFINAE на выражения, и вместе с аргументами decltype и шаблона по умолчанию для шаблонов функций мы можем написать

template<typename T> T&& make();

template<typename Iter, class = decltype( *make<Iter>() )>
void foo(Iter,Iter) {}

void foo(long, int);

int main() {
   foo(2,3); // OK, picks non-template foo
}

В этом случае вывод аргумента шаблона завершится неудачно без предупреждения , потому что компилятор не знает, каким должен быть тип выражения ∗ make () (мы не можем разыменовать int). С помощью небольшого метапрограммирования шаблона и некоторых макросов мы можем довольно близко подойти к наложению произвольных структурных ограничений на параметры шаблона в удобочитаемой форме . Вот как это может выглядеть, если принять соответствующие определения для REQUIRES и RandomAccessIterator:

template <typename Iter
  REQUIRES( RandomAccessIterator<Iter> )
>
void foo(Iter,Iter) {}

HTH, С помощью небольшого метапрограммирования шаблона и некоторых макросов мы можем довольно близко подойти к наложению произвольных структурных ограничений на параметры шаблона в удобочитаемой форме . Вот как это может выглядеть, если принять соответствующие определения для REQUIRES и RandomAccessIterator:

template <typename Iter
  REQUIRES( RandomAccessIterator<Iter> )
>
void foo(Iter,Iter) {}

HTH, С помощью небольшого метапрограммирования шаблонов и некоторых макросов мы можем довольно близко подойти к наложению произвольных структурных ограничений на параметры шаблона в удобочитаемой форме . Вот как это может выглядеть, если принять соответствующие определения для REQUIRES и RandomAccessIterator:

template <typename Iter
  REQUIRES( RandomAccessIterator<Iter> )
>
void foo(Iter,Iter) {}

HTH, S

3
ответ дан 30 November 2019 в 03:43
поделиться
Другие вопросы по тегам:

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