Русский
Русский
English
Статистика
Реклама

Концепты

Стандарт C20 обзор новых возможностей C. Часть 3 Концепты

12.05.2021 14:11:23 | Автор: admin


25 февраля автор курса Разработчик C++ в Яндекс.Практикуме Георгий Осипов рассказал о новом этапе языка C++ Стандарте C++20. В лекции сделан обзор всех основных нововведений Стандарта, рассказывается, как их применять уже сейчас и чем они могут быть полезны.

При подготовке вебинара стояла цель сделать обзор всех ключевых возможностей C++20. Поэтому вебинар получился насыщенным и растянулся на почти 2,5 часа. Для вашего удобства текст мы разбили на шесть частей:

  1. Модули и краткая история C++.
  2. Операция космический корабль.
  3. Концепты.
  4. Ranges.
  5. Корутины.
  6. Другие фичи ядра и стандартной библиотеки. Заключение.

Это третья часть, рассказывающая о концептах и ограничениях в современном C++.

Концепты




Мотивация


Обобщённое программирование ключевое преимущество C++. Я знаю не все языки, но ничего подобного и на таком уровне не видел.

Однако у обобщённого программирования в C++ есть огромный минус: возникающие ошибки это боль. Рассмотрим простую программу, которая сортирует вектор. Взгляните на код и скажите, где в нём ошибка:

#include <vector>#include <algorithm>struct X {    int a;};int main() {    std::vector<X> v = { {10}, {9}, {11} };    // сортируем вектор    std::sort(v.begin(), v.end());}

Я определил структуру X с одним полем int, наполнил вектор объектами этой структуры и пытаюсь его отсортировать.

Надеюсь, вы ознакомились с примером и нашли ошибку. Оглашу ответ: компилятор считает, что ошибка в стандартной библиотеке. Вывод диагностики занимает примерно 60 строк и указывает на ошибку где-то внутри вспомогательного файла xutility. Прочитать и понять диагностику практически невозможно, но программисты C++ делают это ведь пользоваться шаблонами всё равно нужно.



Компилятор показывает, что ошибка в стандартной библиотеке, но это не значит, что нужно сразу писать в Комитет по стандартизации. На самом деле ошибка всё равно в нашей программе. Просто компилятор недостаточно умный, чтобы это понять, и сталкивается с ошибкой, когда заходит в стандартную библиотеку. Распутывая эту диагностику, можно дойти до ошибки. Но это:

  • сложно,
  • не всегда возможно в принципе.

Сформулируем первую проблему обобщённого программирования на C++: ошибки при использовании шаблонов совершенно нечитаемые и диагностируются не там, где сделаны, а в шаблоне.

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

Задачу можно решить хаком SFINAE, написав две функции. Хак использует std::enable_if. Это специальный шаблон в стандартной библиотеке, который содержит ошибку в случае если условие не выполнено. При инстанцировании шаблона компилятор отбрасывает декларации с ошибкой:

#include <type_traits>template <class T>T Abs(T x) {    return x >= 0 ? x : -x;}// вариант для чисел с плавающей точкойtemplate<class T>std::enable_if_t<std::is_floating_point_v<T>, bool>AreClose(T a, T b) {    return Abs(a - b) < static_cast<T>(0.000001);}// вариант для других объектовtemplate<class T>std::enable_if_t<!std::is_floating_point_v<T>, bool> AreClose(T a, T b) {    return a == b;}

В C++17 такую программу можно упростить с помощью if constexpr, хотя это сработает не во всех случаях.

Или ещё пример: я хочу написать функцию Print, которая печатает что угодно. Если ей передали контейнер, она напечатает все элементы, если не контейнер напечатает то, что передали. Мне придётся определить её для всех контейнеров: vector, list, set и других. Это неудобно и неуниверсально.

template<class T>void Print(std::ostream& out, const std::vector<T>& v) {    for (const auto& elem : v) {        out << elem << std::endl;    }}// тут нужно определить функцию для map, set, list, // deque, arraytemplate<class T>void Print(std::ostream& out, const T& v) {    out << v;}

Здесь SFINAE уже не поможет. Вернее, поможет, если постараться, но постараться придётся немало, и код получится монструозный.

Вторая проблема обобщённого программирования: трудно писать разные реализации одной шаблонной функции для разных категорий типов.

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

Что у других


Посмотрим, как дела обстоят в других языках. Я знаю всего один, в котором есть что-то похожее, Haskell.

class Eq a where(==) :: a -> a -> Bool(/=) :: a -> a -> Bool

Это пример класса типов, который требует поддержки операции равно и не равно, выдающих Bool. В C++ то же самое будет реализовано так:

template<typename T>concept Eq =    requires(T a, T b) {        { a == b } -> std::convertible_to<bool>;        { a != b } -> std::convertible_to<bool>;    };

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

В Haskell эти ограничения обязательны. Если не сказать, что будет операция ==, то использовать её не получится. В C++ ограничения нестрогие. Даже если не прописать в концепте операцию, ей всё равно можно пользоваться ведь раньше вообще не было никаких ограничений, а новые стандарты стремятся не нарушать совместимость с предыдущими.

Пример


Дополним код программы, в которой вы недавно искали ошибку:

#include <vector>#include <algorithm>#include <concepts>template<class T>concept IterToComparable =     requires(T a, T b) {        {*a < *b} -> std::convertible_to<bool>;    };    // обратите внимание на IterToComparable вместо слова classtemplate<IterToComparable InputIt>void SortDefaultComparator(InputIt begin, InputIt end) {    std::sort(begin, end);}struct X {    int a;};int main() {    std::vector<X> v = { {10}, {9}, {11} };    SortDefaultComparator(v.begin(), v.end());}

Здесь мы создали концепт IterToComparable. Он показывает, что тип T это итератор, причём указывающий на значения, которые можно сравнивать. Результат сравнения что-то конвертируемое к bool, к примеру сам bool. Подробное объяснение чуть позже, пока что можно не вникать в этот код.

Кстати, ограничения наложены слабые. Здесь не сказано, что тип должен удовлетворять всем свойствам итераторов: например, не требуется, чтобы его можно было инкрементировать. Это простой пример для демонстрации возможностей.

Концепт использовали вместо слова class или typename в конструкции с template. Раньше было template<class InputIt>, а теперь слово class заменили на имя концепта. Значит, параметр InputIt должен удовлетворять ограничению.

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

  • Что случилось? Вызов функции с невыполненным ограничением.
  • Какое ограничение не удовлетворено? IterToComparable<InputIt>
  • Почему? Выражение ((* a) < (* b)) некорректно.


Вывод компилятора читаемый и занимает 16 строк вместо 60.

main.cpp: In function 'int main()':main.cpp:24:45: error: **use of function** 'void SortDefaultComparator(InputIt, InputIt) [with InputIt = __gnu_cxx::__normal_iterator<X*, std::vector<X> >]' **with unsatisfied constraints**   24 |     SortDefaultComparator(v.begin(), v.end());      |                                             ^main.cpp:12:6: note: declared here   12 | void SortDefaultComparator(InputIt begin, InputIt end) {      |      ^~~~~~~~~~~~~~~~~~~~~main.cpp:12:6: note: constraints not satisfiedmain.cpp: In instantiation of 'void SortDefaultComparator(InputIt, InputIt) [with InputIt = __gnu_cxx::__normal_iterator<X*, std::vector<X> >]':main.cpp:24:45:   required from heremain.cpp:6:9:   **required for the satisfaction of 'IterToComparable<InputIt>'** [with InputIt = __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > >]main.cpp:7:5:   in requirements with 'T a', 'T b' [with T = __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > >]main.cpp:8:13: note: the required **expression '((* a) < (* b))' is invalid**, because    8 |         {*a < *b} -> std::convertible_to<bool>;      |          ~~~^~~~main.cpp:8:13: error: no match for 'operator<' (operand types are 'X' and 'X')

Добавим недостающую операцию сравнения в структуру, и программа скомпилируется без ошибок концепт удовлетворён:

struct X {    auto operator<=>(const X&) const = default;    int a;};

Точно так же можно улучшить второй пример, с enable_if. Этот шаблон больше не нужен. Вместо него используем стандартный концепт is_floating_point_v<T>. Получим две функции: одну для чисел с плавающей точкой, другую для прочих объектов:

#include <type_traits>template <class T>T Abs(T x) {    return x >= 0 ? x : -x;}// вариант для чисел с плавающей точкойtemplate<class T>requires(std::is_floating_point_v<T>)bool AreClose(T a, T b) {    return Abs(a - b) < static_cast<T>(0.000001);}// вариант для других объектовtemplate<class T>bool AreClose(T a, T b) {    return a == b;}

Модифицируем и функцию печати. Если вызов a.begin() и a.end() допустим, будем считать a контейнером.

#include <iostream>#include <vector>template<class T>concept HasBeginEnd =     requires(T a) {        a.begin();        a.end();    };template<HasBeginEnd T>void Print(std::ostream& out, const T& v) {    for (const auto& elem : v) {        out << elem << std::endl;    }}template<class T>void Print(std::ostream& out, const T& v) {    out << v;}

Опять же, это неидеальный пример, поскольку контейнер не просто что-то с begin и end, к нему предъявляется ещё масса требований. Но уже неплохо.

Лучше всего использовать готовый концепт, как is_floating_point_v из предыдущего примера. Для аналога контейнеров в стандартной библиотеке тоже есть концепт std::ranges::input_range. Но это уже совсем другая история.

Теория


Пришло время понять, что такое концепт. Ничего сложного тут на самом деле нет:

Концепт это имя для ограничения.

Мы свели его к другому понятию, определение которого уже содержательно, но может показаться странным:

Ограничение это шаблонное булево выражение.

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

Самое простое ограничение это true. Ему удовлетворяет любой тип.

template<class T> concept C1 = true;

Для ограничений доступны булевы операции и комбинации других ограничений:

template <class T>concept Integral = std::is_integral<T>::value;template <class T>concept SignedIntegral = Integral<T> &&                         std::is_signed<T>::value;template <class T>concept UnsignedIntegral = Integral<T> &&                           !SignedIntegral<T>;

В ограничениях можно использовать выражения и даже вызывать функции. Но функции должны быть constexpr они вычисляются на этапе компиляции:

template<typename T>constexpr bool get_value() { return T::value; } template<typename T>    requires (sizeof(T) > 1 && get_value<T>())void f(T); // #1 void f(int); // #2 void g() {    f('A'); // вызывает #2.}

И список возможностей этим не исчерпывается.

Для ограничений есть отличная возможность: проверка корректности выражения того, что оно компилируется без ошибок. Посмотрите на ограничение Addable. В скобках написано a + b. Условия ограничения выполняются тогда, когда значения a и b типа T допускают такую запись, то есть T имеет определённую операцию сложения:

template<class T>concept Addable =requires (T a, T b) {    a + b;};

Более сложный пример вызов функций swap и forward. Ограничение выполнится тогда, когда этот код скомпилируется без ошибок:

template<class T, class U = T>concept Swappable = requires(T&& t, U&& u) {    swap(std::forward<T>(t), std::forward<U>(u));    swap(std::forward<U>(u), std::forward<T>(t));};

Ещё один вид ограничений проверка корректности типа:

template<class T> using Ref = T&;template<class T> concept C =requires {    typename T::inner;     typename S<T>;         typename Ref<T>;   };

Ограничение может требовать не только корректность выражения, но и чтобы тип его значения чему-то соответствовал. Здесь мы записываем:

  • выражение в фигурных скобках,
  • ->,
  • другое ограничение.

template<class T> concept C1 =requires(T x) {    {x + 1} -> std::same_as<int>;};

Ограничение в данном случае same_as<int>
То есть тип выражения x + 1 должен быть в точности int.

Обратите внимание, что после стрелки идёт ограничение, а не сам тип. Посмотрите ещё один пример концепта:

template<class T> concept C2 =requires(T x) {    {*x} -> std::convertible_to<typename T::inner>;    {x * 1} -> std::convertible_to<T>;};

В нём два ограничения. Первое указывает, что:

  • выражение *x корректно;
  • тип T::inner корректен;
  • тип *x конвертируется к T::inner.

В одной строчке целых три требования. Второе указывает, что:

  • выражение x * 1 синтаксически корректно;
  • его результат конвертируется к T.

Перечисленными способами можно формировать любые ограничения. Это очень весело и приятно, но вы быстро наигрались бы с ними и забыли, если бы их нельзя было использовать. А использовать ограничения и концепты можно для всего, что поддерживает шаблоны. Конечно, основное применение это функции и классы.

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

Ограничение для функции можно написать в трёх разных местах:

// Вместо слова class или typename в шаблонную декларацию.// Поддерживаются только концепты.template<Incrementable T>void f(T arg);// Использовать ключевое слово requires. В таком случае их можно вставить // в любое из двух мест.// Годится даже неименованное ограничение.template<class T>requires Incrementable<T>void f(T arg);template<class T>void f(T arg) requires Incrementable<T>;

И есть ещё четвёртый способ, который выглядит совсем магически:

void f(Incrementable auto arg);

Тут использован неявный шаблон. До C++20 они были доступны только в лямбдах. Теперь можно использовать auto в сигнатурах любых функций: void f(auto arg). Более того, перед этим auto допустимо имя концепта, как в примере. Кстати, в лямбдах теперь доступны явные шаблоны, но об этом позже.

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

Для класса возможностей меньше всего два способа. Но этого вполне хватает:

template<Incrementable T>class X {};template<class T>requires Incrementable<T>class Y {};

Антон Полухин, помогавший при подготовке этой статьи, заметил, что слово requires можно использовать не только при декларировании функций, классов и концептов, но и прямо в теле функции или метода. Например, оно пригодится, если вы пишете функцию, наполняющую контейнер неизвестного заранее типа:

template<class T> void ReadAndFill(T& container, int size) {     if constexpr (requires {container.reserve(size); }) {         container.reserve(size);     }    // заполняем контейнер }

Эта функция будет одинаково хорошо работать как с vector, так и с list, причём для первого будет вызываться нужный в его случае метод reserve.

Полезно использовать requires и в static_assert. Так можно проверять выполнение не только обычных условий, но и корректность произвольного кода, наличие у типов методов и операций.

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

template<class T, class U>concept Derived = std::is_base_of<U, T>::value; template<Derived<Other> X>void f(X arg);

У концепта Derived два шаблонных параметра. В декларации f один из них я указал, а второй класс X, который и проверяется. Аудитории был задан вопрос, какой параметр я указал: T или U; получилось Derived<Other, X> или Derived<X, Other>?

Ответ неочевиден: это Derived<X, Other>. Указывая параметр Other, мы указали второй шаблонный параметр. Результаты голосования разошлись:

  • правильных ответов 8 (61.54%);
  • неправильных ответов 5 (38.46%).

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

Итак, я рассказал как определять новые концепты, но это нужно не всегда в стандартной библиотеке их уже предостаточно. На этом слайде приведены концепты, которые находятся в заголовочном файле <concepts>.



Это ещё не всё: концепты для проверки разных типов итераторов есть в <iterator>, <ranges> и других библиотеках.



Статус




Концепты есть везде, но в Visual Studio пока что не полностью:

  • GCC. Хорошо поддерживается с версии 10;
  • Clang. Полная поддержка в версии 10;
  • Visual Studio. Поддерживается VS 2019, но не полностью реализован requires.

Заключение


Во время трансляции мы опросили аудиторию, нравится ли ей эта функция. Результаты опроса:

  • Суперфича 50 (92.59%)
  • Так себе фича 0 (0.00%)
  • Пока неясно 4 (7.41%)

Подавляющее большинство проголосовавших оценило концепты. Я тоже считаю это крутой фичей. Спасибо Комитету!

Читателям Хабра, как и слушателям вебинара, дадим возможность оценить нововведения.
Подробнее..

Производительность компилятора при работе с концептами в C20

20.06.2021 18:15:44 | Автор: admin

Привет, меня зовут Александр, я старший разработчик ПО в Центре разработкиOrionInnovation. Хочу признаться, я люблю рассказывать про C++ и не только на различных митапах и конференциях.Ивотядобрался доХабра. НаCppConfRussiaPiter2020 я рассказывал про концепты и послевыступленияполучилочень много вопросов про производительность компилятора при работе сними.Замеры производительности не были цельюмоегодоклада:мне было известно, что концепты компилируются с примерно такой же скоростью, что и обычные метапрограммы,адодетального сравнения я смог добраться совершенно недавно.Спешуподелиться результатом!

Несколько слов о концептах

Концептыпереосмыслениеметапрограммирования, аналогичноеconstexpr.Еслиconstexprэто про вычисление выраженийво время компиляции, будь то факториал, экспонента и так далее, то концептыэто про перегрузки, специализации, условия существования сущностей.Вобщем, про чистоеметапрограммирование. Иными словами, в C++20 появилась возможность писать конструкциибез единой, привычной для нас треугольной скобки, тем самым получая возможность быстро и читаемо описать какую-либо перегрузку или специализацию:

// #1void increment(auto & arg) requires requires { ++arg; }; // #2void increment(auto &);struct Incrementable { Incrementable & operator++() { return *this; } };struct NonIncrementable {};void later() {    Incrementable     i;    NonIncrementable ni;    increment(i);  // Вызывается #1    increment(ni); // Вызывается #2}

О том, как всё это работает, есть море информации,например, отличный гайд "Концепты: упрощаем реализацию классов STD Utility" по мотивам выступления Андрея Давыдова на C++ Russia 2019. Ну а мы сфокусируемся на том, какой ценой достигается подобный функционал, чтобы убедиться, чтоэтонетолькопросто, быстро и красиво, ноещёи эффективно.

Описание эксперимента

Итак, мы будем наблюдать за следующими показателями:

  1. Время компиляции

  1. Размер объектного файла

  1. Количество символов в записи (или же количество кода), в некоторых случаях

Прежде чем мы начнём несколько важных уточнений:

  • Во-первых, при подсчёте количества символов в записи мы будем считать все не пустые.

  • Во-вторых, в данной статье мы посмотрим лишь на самые простые (буквально несколько строк) случаи, чтобы быть уверенными на 100%, что мы сравниваем абсолютно аналогичные фрагменты кода.

  • В-третьих, поскольку компилируемые примеры крайне просты, время компиляции выражается в десятках миллисекунд.Чтобы исключитьпогрешность, длявремени компиляции мы будем использовать усреднённые значения за100запусков.

В замерах будут участвовать clang 12.0.0 и g++ 10.3.0, как с полной оптимизацией, так и без неё.

В качестве операционной системы выступит Ubuntu 16.04, запущенная на Windows 10 через WSL2.На всякий случай прилагаю характеристики ПК:

Характеристики ПК
------------------System Information------------------         Operating System: Windows 10 Enterprise 64-bit (10.0, Build 19043) (19041.vb_release.191206-1406)                 Language: Russian (Regional Setting: Russian)      System Manufacturer: Dell Inc.             System Model: Latitude 5491                     BIOS: 1.12.0 (type: UEFI)                Processor: Intel(R) Core(TM) i5-8300H CPU @ 2.30GHz (8 CPUs), ~2.3GHz                   Memory: 32768MB RAM      Available OS Memory: 32562MB RAM                Page File: 9995MB used, 27430MB available------------------------Disk & DVD/CD-ROM Drives------------------------      Drive: C: Free Space: 26.5 GBTotal Space: 243.0 GBFile System: NTFS      Model: SAMSUNG SSD PM871b M.2 2280 256GB

Эксперименты

Посленеобходимыхотступлениймы можем,наконец,начать эксперименты.

Эксперимент 1: Эволюция метапрограммирования

Для началапосмотрим на то, как компиляторы справляются с созданием перегрузки функции для инкрементируемых инеинкрементируемыхтипов данных аргумента. Компилируемый код для C++ 03, 17 и 20 представлены ниже. Один из показателей, а именнообъем кода, можно оценить уже сейчас: видно, что количество кода существенно сокращается по мере эволюции языка, уступая место читаемости и простоте.

Код
incrementable_03.cpp
// copied from boosttemplate<bool C, typename T = void>struct enable_if { typedef T type; };template<typename T>struct enable_if<false, T> {};namespace is_inc {    typedef char (&yes)[1]; typedef char (&no)[2];struct tag {};struct any { template &lt;class T&gt; any(T const&amp;); };tag operator++(any const &amp;);template&lt;typename T&gt;static yes test(T const &amp;);static no test(tag);template&lt;typename _T&gt; struct IsInc{    static _T &amp; type_value;    static const bool value = sizeof(yes) == sizeof(test(++type_value));};}template<typename T>struct IsInc : public is_inc::IsInc<T> {};template<class Ty>typename enable_if<IsInc<Ty>::value>::type increment(Ty &);template<class Ty>typename enable_if<!IsInc<Ty>::value>::type increment(Ty &);struct Incrementable { Incrementable & operator++() { return *this; } };struct NonIncrementable {};void later() {    Incrementable     i;    NonIncrementable ni;    increment(i);    increment(ni);}
incrementable_17.cpp
#include <type_traits>template<class, class = std::void_t<>>struct IsInc : std::false_type {};template<class T>struct IsInc<T, std::void_t<decltype( ++std::declval<T&>() )>>    : std::true_type{};template<class Ty>std::enable_if_t<IsInc<Ty>::value> increment(Ty &);template<class Ty>std::enable_if_t<!IsInc<Ty>::value> increment(Ty &);struct Incrementable { Incrementable & operator++() { return *this; } };struct NonIncrementable {};void later() {    Incrementable     i;    NonIncrementable ni;    increment(i);    increment(ni);}
incrementable_20.cpp
void increment(auto & arg) requires requires { ++arg; };void increment(auto &);struct Incrementable { Incrementable & operator++() { return *this; } };struct NonIncrementable {};void later() {    Incrementable     i;    NonIncrementable ni;    increment(i);    increment(ni);}

Давайте взглянем на результаты:

Файл

Компиляция

Время, мс

Размер объектного файла, байт

Количество символов, шт

incrementable_03.cpp

clang

O0

43,02

1304

782

incrementable_17.cpp

clang

O0

67,46

1320

472

incrementable_20.cpp

clang

O0

43,42

1304

230

incrementable_03.cpp

clang

O3

47,21

1296

782

incrementable_17.cpp

clang

O3

77,77

1304

472

incrementable_20.cpp

clang

O3

45,70

1288

230

incrementable_03.cpp

gcc

O0

19,89

1568

782

incrementable_17.cpp

gcc

O0

34,71

1568

472

incrementable_20.cpp

gcc

O0

17,62

1480

230

incrementable_03.cpp

gcc

O3

18,44

1552

782

incrementable_17.cpp

gcc

O3

38,94

1552

472

incrementable_20.cpp

gcc

O3

18,57

1464

230

Как уже отмечалось ранее,количество кода существенно уменьшается по мере развития языка: c 782 до 472 и затем до 230.Разницапочти в 3,5 раза, если сравнитьС++20 и С++03 (на самом деле даже больше,т.к.порядка150170символов во всех примерахтестирующий код). Размеры объектного файла также постепенно уменьшаются. Что же современем компиляции? Странно, новремя компиляции 03 и 20 примерно равно, а вот в С++17в два раза больше. Давайте взглянем на код наших примеров: помимо всего прочего, в глаза бросается#includeв случае C++17. Давайте реализуемdeclval,enable_ifиvoid_tи проверим:

incrementable_no_tt.cpp
template<bool C, typename T = void>struct enable_if { typedef T type; };template<typename T>struct enable_if<false, T> {};template<bool B, typename T = void>using enable_if_t = typename enable_if<B, T>::type;template<typename ...>using void_t = void;template<class T>T && declval() noexcept;template<class, class = void_t<>>struct IsInc {    constexpr static bool value = false;};template<class T>struct IsInc<T, void_t<decltype( ++declval<T&>() )>>{    constexpr static bool value = true;};template<class Ty>enable_if_t<IsInc<Ty>::value> increment(Ty &);template<class Ty>enable_if_t<!IsInc<Ty>::value> increment(Ty &);struct Incrementable { Incrementable & operator++() { return *this; } };struct NonIncrementable {};void later() {    Incrementable     i;    NonIncrementable ni;    increment(i);    increment(ni);}

И давайте обновим нашу таблицу:

Файл

Компиляция

Время, мс

Размер объектного файла, байт

Количество символов, шт

incrementable_03.cpp

clang

O0

43,02

1304

782

incrementable_17_no_tt.cpp

clang

O0

44,498

1320

714

incrementable_20.cpp

clang

O0

43,419

1304

230

incrementable_03.cpp

clang

O3

47,205

1296

782

incrementable_17_no_tt.cpp

clang

O3

47,327

1312

714

incrementable_20.cpp

clang

O3

45,704

1288

230

incrementable_03.cpp

gcc

O0

19,885

1568

782

incrementable_17_no_tt.cpp

gcc

O0

21,163

1584

714

incrementable_20.cpp

gcc

O0

17,619

1480

230

incrementable_03.cpp

gcc

O3

18,442

1552

782

incrementable_17_no_tt.cpp

gcc

O3

19,057

1568

714

incrementable_20.cpp

gcc

O3

18,566

1464

230

Время компиляции на 17 стандарте нормализовалось и стало практически равно времени компиляции 03 и 20, однако количество кода стало близко к самому тяжёлому, базовому варианту. Так что, если у вас есть под рукой C++20 и нужно написать какую-то простую мета-перегрузку,смело можно использовать концепты. Это читабельнее, компилируется примерно с такой же скоростью, а результат компиляции занимает меньше места.

Эксперимент 2: Ограничения для методов

Давайте взглянем на еще одну особенность: ограничение для функции или метода (в том числе и для конструкторов и деструкторов) на примере типаOptionalLike, имеющего деструктор по умолчанию в случае, если помещаемый объект тривиален, а иначедеструктор, выполняющийдеинициализациюкорректно. Код представлен ниже:

Код
optional_like_17.cpp
#include <type_traits>#include <string>template<typename T, typename = void>struct OptionalLike {    ~OptionalLike() {        /* Calls d-tor manually */    }};template<typename T>struct OptionalLike<T, std::enable_if_t<std::is_trivially_destructible<T>::value>>{    ~OptionalLike() = default;};void later() {    OptionalLike<int>         oli;    OptionalLike<std::string> ols;}
optional_like_20.cpp
#include <type_traits>#include <string>template<typename T>struct OptionalLike{    ~OptionalLike() {        /* Calls d-tor manually */    }    ~OptionalLike() requires (std::is_trivially_destructible<T>::value) = default;};void later() {    OptionalLike<int>         oli;    OptionalLike<std::string> ols;}

Давайте взглянем на результаты:

Файл

Компиляция

Время, мс

Размер объектного файла, байт

Количество символов, шт

optional_like_17.cpp

clang

O0

487,62

1424

319

optional_like_20.cpp

clang

O0

616,8

1816

253

optional_like_17.cpp

clang

O3

490,07

944

319

optional_like_20.cpp

clang

O3

627,64

1024

253

optional_like_17.cpp

gcc

O0

202,29

1968

319

optional_like_20.cpp

gcc

O0

505,82

1968

253

optional_like_17.cpp

gcc

O3

205,55

1200

319

optional_like_20.cpp

gcc

O3

524,54

1200

253

Мы видим, что новый вариант выглядит более читабельным и лаконичным (253 символа против 319 у классического), однако платим за это временем компиляции: оба компилятора как с оптимизацией, так и без показали худшее время компиляции в случае с концептами. GCC аж в 22,5 раза медленнее. При этом размер объектного файла уgccне изменяется вовсе, а в случаеclangбольше для концептов. Классический компромисс: либо меньше кода, но дольше компиляция, либо больше кода, но быстрее компиляция.

Эксперимент 3: Влияние использования концептов на время компиляции

Мы знаем, что накладывать ограничения на типможноиспользуя именованные наборы требований, они же концепты.Такжеможно указать требования непосредственно в момент объявления шаблонной сущности. Давайте посмотрим, есть ли разница с точки зрения компилятора. Компилировать будем следующие фрагменты:

Код
inline.cpp
template<typename T>void foo() requires (sizeof(T) >= 4) { }template<typename T>void foo() {}void later() {    foo<char>();    foo<int>();}
concept.cpp
template<typename T>concept IsBig = sizeof(T) >= 4;template<typename T>void foo() requires IsBig<T> { }template<typename T>void foo() {}void later() {    foo<char>();    foo<int>();}

Сразу взглянем на результаты:

Файл

Компиляция

Время, мс

Размер объектного файла, байт

inline.cpp

clang

O0

38,666

1736

concept.cpp

clang

O0

39,868

1736

concept.cpp

clang

O3

42,578

1040

inline.cpp

clang

O3

43,610

1040

inline.cpp

gcc

O0

14,598

1976

concept.cpp

gcc

O0

14,640

1976

concept.cpp

gcc

O3

14,872

1224

inline.cpp

gcc

O3

14,951

1224

Как мы можем заметить,размеры получившихся объектных файлов идентичны, а показатели времени компиляции практически совпадают. Так что при выборе концепт илиinline-требованиеможнонезадумываться о производительности компилятора.

Эксперимент 4: Варианты ограничения функции

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

  • Имя концепта вместоtypename

  • Requires clauseпослеtemplate<>

  • Имя концепта рядом сauto

  • Trailing requiresclause

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

Код
instead_of_typename.cpp
template<typename T>concept IsBig = sizeof(T) >= 4;template<IsBig T>void foo(T const &) { }template<typename T>void foo(T const &) {}void later() {    foo<char>('a');    foo<int>(1);}
after_template.cpp
template<typename T>concept IsBig = sizeof(T) >= 4;template<typename T>    requires IsBig<T>void foo(T const &) { }template<typename T>void foo(T const &) {}void later() {    foo<char>('a');    foo<int>(1);}
with_auto.cpp
template<typename T>concept IsBig = sizeof(T) >= 4;template<typename T>void foo(IsBig auto const &) { }template<typename T>void foo(auto const &) {}void later() {    foo<char>('a');    foo<int>(1);}
requires_clause.cpp
template<typename T>concept IsBig = sizeof(T) >= 4;template<typename T>void foo(T const &) requires IsBig<T> { }template<typename T>void foo(T const &) {}void later() {    foo<char>('a');    foo<int>(1);}

А вот и результаты:

Файл

Компиляция

Время, мс

Размер объектного файла, байт

function_with_auto.cpp

clang

O0

40,878

1760

function_after_template.cpp

clang

O0

41,947

1760

function_requires_clause.cpp

clang

O0

42,551

1760

function_instead_of_typename.cpp

clang

O0

46,893

1760

function_with_auto.cpp

clang

O3

43,928

1024

function_requires_clause.cpp

clang

O3

45,176

1032

function_after_template.cpp

clang

O3

45,275

1032

function_instead_of_typename.cpp

clang

O3

50,42

1032

function_requires_clause.cpp

gcc

O0

16,561

2008

function_with_auto.cpp

gcc

O0

16,692

2008

function_after_template.cpp

gcc

O0

17,032

2008

function_instead_of_typename.cpp

gcc

O0

17,802

2016

function_requires_clause.cpp

gcc

O3

16,233

1208

function_with_auto.cpp

gcc

O3

16,711

1208

function_after_template.cpp

gcc

O3

17,216

1208

function_instead_of_typename.cpp

gcc

O3

18,315

1216

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

  • Вариант с использованием имени концепта вместоtypenameоказался самым медленным во всех случаях.

  • Вариантыtrailing requiresclauseили использование концепта рядом сautoоказались самыми быстрыми.

  • Варианты, где присутствуетtemplate<>на510% медленнее остальных.

  • Размерыобъектных файлов изменяются незначительно, однако вариант с именем концепта вместоtypenameоказался самым объемным в случаеgcc, а вариант сautoоказался наименее объемным в случаеclang.

Эксперимент 5: Влияние сложности концепта на время компиляции

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

Код
concept_complexity_1.cpp
template<typename T>concept ConceptA = sizeof(T) >= 1;template<typename T>concept TestedConcept = ConceptA<T>;void foo(TestedConcept auto const &) {}void foo(auto const &) {}void later() {    int i { 0 };    int * ip = &i;    foo(i);    foo(ip);}
concept_complexity_2.cpp
template<typename T>concept ConceptA = sizeof(T) >= 1;template<typename T>concept ConceptB =  requires(T i, int x) {    { i++     } noexcept -> ConceptA;    { ++i     } noexcept -> ConceptA;    { i--     } noexcept -> ConceptA;    { --i     } noexcept -> ConceptA;    { i + i   } noexcept -> ConceptA;    { i - i   } noexcept -> ConceptA;    { i += i  } noexcept -> ConceptA;    { i -= i  } noexcept -> ConceptA;    { i * i      } noexcept -> ConceptA;    { i / i      } noexcept -> ConceptA;    { i % i      } noexcept -> ConceptA;    { i *= i     } noexcept -> ConceptA;    { i /= i     } noexcept -> ConceptA;    { i %= i     } noexcept -> ConceptA;    { i |  i     } noexcept -> ConceptA;    { i &  i     } noexcept -> ConceptA;    { i |= i     } noexcept -> ConceptA;    { i &= i     } noexcept -> ConceptA;    { ~i          } noexcept -> ConceptA;    { i ^  i      } noexcept -> ConceptA;    { i << x      } noexcept -> ConceptA;    { i >> x      } noexcept -> ConceptA;    { i ^=  i      } noexcept -> ConceptA;    { i <<= x      } noexcept -> ConceptA;    { i >>= x      } noexcept -> ConceptA;};template<typename T>concept ConceptC =  requires(T i, int x) {    { i++     } noexcept -> ConceptB;    { ++i     } noexcept -> ConceptB;    { i--     } noexcept -> ConceptB;    { --i     } noexcept -> ConceptB;    { i + i   } noexcept -> ConceptB;    { i - i   } noexcept -> ConceptB;    { i += i  } noexcept -> ConceptB;    { i -= i  } noexcept -> ConceptB;    { i * i      } noexcept -> ConceptB;    { i / i      } noexcept -> ConceptB;    { i % i      } noexcept -> ConceptB;    { i *= i     } noexcept -> ConceptB;    { i /= i     } noexcept -> ConceptB;    { i %= i     } noexcept -> ConceptB;    { i |  i     } noexcept -> ConceptB;    { i &  i     } noexcept -> ConceptB;    { i |= i     } noexcept -> ConceptB;    { i &= i     } noexcept -> ConceptB;    { ~i          } noexcept -> ConceptB;    { i ^  i      } noexcept -> ConceptB;    { i << x      } noexcept -> ConceptB;    { i >> x      } noexcept -> ConceptB;    { i ^=  i      } noexcept -> ConceptB;    { i <<= x      } noexcept -> ConceptB;    { i >>= x      } noexcept -> ConceptB;};template<typename T>concept ConceptD =  requires(T i, int x) {    { i++     } noexcept -> ConceptC;    { ++i     } noexcept -> ConceptC;    { i--     } noexcept -> ConceptC;    { --i     } noexcept -> ConceptC;    { i + i   } noexcept -> ConceptC;    { i - i   } noexcept -> ConceptC;    { i += i  } noexcept -> ConceptC;    { i -= i  } noexcept -> ConceptC;    { i * i      } noexcept -> ConceptC;    { i / i      } noexcept -> ConceptC;    { i % i      } noexcept -> ConceptC;    { i *= i     } noexcept -> ConceptC;    { i /= i     } noexcept -> ConceptC;    { i %= i     } noexcept -> ConceptC;    { i |  i     } noexcept -> ConceptC;    { i &  i     } noexcept -> ConceptC;    { i |= i     } noexcept -> ConceptC;    { i &= i     } noexcept -> ConceptC;    { ~i          } noexcept -> ConceptC;    { i ^  i      } noexcept -> ConceptC;    { i << x      } noexcept -> ConceptC;    { i >> x      } noexcept -> ConceptC;    { i ^=  i      } noexcept -> ConceptC;    { i <<= x      } noexcept -> ConceptC;    { i >>= x      } noexcept -> ConceptC;};template<typename T>concept TestedConcept = ConceptA<T> && ConceptB<T> && ConceptC<T> && ConceptD<T>;void foo(TestedConcept auto const &) {}void foo(auto const &) {}void later() {    int i { 0 };    int * ip = &i;    foo(i);    foo(ip);}
concept_complexity_3.cpp
template<typename T>concept ConceptA = sizeof(T) >= 1;template<typename T>concept ConceptB =  requires(T i, int x) {    { i++     } noexcept -> ConceptA;    { ++i     } noexcept -> ConceptA;    { i--     } noexcept -> ConceptA;    { --i     } noexcept -> ConceptA;    { i + i   } noexcept -> ConceptA;    { i - i   } noexcept -> ConceptA;    { i += i  } noexcept -> ConceptA;    { i -= i  } noexcept -> ConceptA;    { i * i      } noexcept -> ConceptA;    { i / i      } noexcept -> ConceptA;    { i % i      } noexcept -> ConceptA;    { i *= i     } noexcept -> ConceptA;    { i /= i     } noexcept -> ConceptA;    { i %= i     } noexcept -> ConceptA;    { i |  i     } noexcept -> ConceptA;    { i &  i     } noexcept -> ConceptA;    { i |= i     } noexcept -> ConceptA;    { i &= i     } noexcept -> ConceptA;    { ~i          } noexcept -> ConceptA;    { i ^  i      } noexcept -> ConceptA;    { i << x      } noexcept -> ConceptA;    { i >> x      } noexcept -> ConceptA;    { i ^=  i      } noexcept -> ConceptA;    { i <<= x      } noexcept -> ConceptA;    { i >>= x      } noexcept -> ConceptA;};template<typename T>concept ConceptC =  requires(T i, int x) {    { i++     } noexcept -> ConceptB;    { ++i     } noexcept -> ConceptB;    { i--     } noexcept -> ConceptB;    { --i     } noexcept -> ConceptB;    { i + i   } noexcept -> ConceptB;    { i - i   } noexcept -> ConceptB;    { i += i  } noexcept -> ConceptB;    { i -= i  } noexcept -> ConceptB;    { i * i      } noexcept -> ConceptB;    { i / i      } noexcept -> ConceptB;    { i % i      } noexcept -> ConceptB;    { i *= i     } noexcept -> ConceptB;    { i /= i     } noexcept -> ConceptB;    { i %= i     } noexcept -> ConceptB;    { i |  i     } noexcept -> ConceptB;    { i &  i     } noexcept -> ConceptB;    { i |= i     } noexcept -> ConceptB;    { i &= i     } noexcept -> ConceptB;    { ~i          } noexcept -> ConceptB;    { i ^  i      } noexcept -> ConceptB;    { i << x      } noexcept -> ConceptB;    { i >> x      } noexcept -> ConceptB;    { i ^=  i      } noexcept -> ConceptB;    { i <<= x      } noexcept -> ConceptB;    { i >>= x      } noexcept -> ConceptB;};template<typename T>concept ConceptD =  requires(T i, int x) {    { i++     } noexcept -> ConceptC;    { ++i     } noexcept -> ConceptC;    { i--     } noexcept -> ConceptC;    { --i     } noexcept -> ConceptC;    { i + i   } noexcept -> ConceptC;    { i - i   } noexcept -> ConceptC;    { i += i  } noexcept -> ConceptC;    { i -= i  } noexcept -> ConceptC;    { i * i      } noexcept -> ConceptC;    { i / i      } noexcept -> ConceptC;    { i % i      } noexcept -> ConceptC;    { i *= i     } noexcept -> ConceptC;    { i /= i     } noexcept -> ConceptC;    { i %= i     } noexcept -> ConceptC;    { i |  i     } noexcept -> ConceptC;    { i &  i     } noexcept -> ConceptC;    { i |= i     } noexcept -> ConceptC;    { i &= i     } noexcept -> ConceptC;    { ~i          } noexcept -> ConceptC;    { i ^  i      } noexcept -> ConceptC;    { i << x      } noexcept -> ConceptC;    { i >> x      } noexcept -> ConceptC;    { i ^=  i      } noexcept -> ConceptC;    { i <<= x      } noexcept -> ConceptC;    { i >>= x      } noexcept -> ConceptC;};template<typename T>concept ConceptE =  requires(T i, int x) {    { i++     } noexcept -> ConceptD;    { ++i     } noexcept -> ConceptD;    { i--     } noexcept -> ConceptD;    { --i     } noexcept -> ConceptD;    { i + i   } noexcept -> ConceptD;    { i - i   } noexcept -> ConceptD;    { i += i  } noexcept -> ConceptD;    { i -= i  } noexcept -> ConceptD;    { i * i      } noexcept -> ConceptD;    { i / i      } noexcept -> ConceptD;    { i % i      } noexcept -> ConceptD;    { i *= i     } noexcept -> ConceptD;    { i /= i     } noexcept -> ConceptD;    { i %= i     } noexcept -> ConceptD;    { i |  i     } noexcept -> ConceptD;    { i &  i     } noexcept -> ConceptD;    { i |= i     } noexcept -> ConceptD;    { i &= i     } noexcept -> ConceptD;    { ~i          } noexcept -> ConceptD;    { i ^  i      } noexcept -> ConceptD;    { i << x      } noexcept -> ConceptD;    { i >> x      } noexcept -> ConceptD;    { i ^=  i      } noexcept -> ConceptD;    { i <<= x      } noexcept -> ConceptD;    { i >>= x      } noexcept -> ConceptD;};template<typename T>concept ConceptF =  requires(T i, int x) {    { i++     } noexcept -> ConceptE;    { ++i     } noexcept -> ConceptE;    { i--     } noexcept -> ConceptE;    { --i     } noexcept -> ConceptE;    { i + i   } noexcept -> ConceptE;    { i - i   } noexcept -> ConceptE;    { i += i  } noexcept -> ConceptE;    { i -= i  } noexcept -> ConceptE;    { i * i      } noexcept -> ConceptE;    { i / i      } noexcept -> ConceptE;    { i % i      } noexcept -> ConceptE;    { i *= i     } noexcept -> ConceptE;    { i /= i     } noexcept -> ConceptE;    { i %= i     } noexcept -> ConceptE;    { i |  i     } noexcept -> ConceptE;    { i &  i     } noexcept -> ConceptE;    { i |= i     } noexcept -> ConceptE;    { i &= i     } noexcept -> ConceptE;    { ~i          } noexcept -> ConceptE;    { i ^  i      } noexcept -> ConceptE;    { i << x      } noexcept -> ConceptE;    { i >> x      } noexcept -> ConceptE;    { i ^=  i      } noexcept -> ConceptE;    { i <<= x      } noexcept -> ConceptE;    { i >>= x      } noexcept -> ConceptE;};template<typename T>concept ConceptG =  requires(T i, int x) {    { i++     } noexcept -> ConceptF;    { ++i     } noexcept -> ConceptF;    { i--     } noexcept -> ConceptF;    { --i     } noexcept -> ConceptF;    { i + i   } noexcept -> ConceptF;    { i - i   } noexcept -> ConceptF;    { i += i  } noexcept -> ConceptF;    { i -= i  } noexcept -> ConceptF;    { i * i      } noexcept -> ConceptF;    { i / i      } noexcept -> ConceptF;    { i % i      } noexcept -> ConceptF;    { i *= i     } noexcept -> ConceptF;    { i /= i     } noexcept -> ConceptF;    { i %= i     } noexcept -> ConceptF;    { i |  i     } noexcept -> ConceptF;    { i &  i     } noexcept -> ConceptF;    { i |= i     } noexcept -> ConceptF;    { i &= i     } noexcept -> ConceptF;    { ~i          } noexcept -> ConceptF;    { i ^  i      } noexcept -> ConceptF;    { i << x      } noexcept -> ConceptF;    { i >> x      } noexcept -> ConceptF;    { i ^=  i      } noexcept -> ConceptF;    { i <<= x      } noexcept -> ConceptF;    { i >>= x      } noexcept -> ConceptF;};template<typename T>concept TestedConcept = ConceptA<T> && ConceptB<T> && ConceptC<T> && ConceptD<T> &&                                       ConceptE<T> && ConceptF<T> && ConceptG<T>;void foo(TestedConcept auto const &) {}void foo(auto const &) {}void later() {    int i { 0 };    int * ip = &i;    foo(i);    foo(ip);}

Давайте взглянем на результат:

Файл

Компиляция

Время, мс

Количество символов, шт

concept_complexity_1.cpp

clang

O0

37,441

201

concept_complexity_2.cpp

clang

O0

38,211

2244

concept_complexity_3.cpp

clang

O0

39,989

4287

concept_complexity_1.cpp

clang

O3

40,062

201

concept_complexity_2.cpp

clang

O3

40,659

2244

concept_complexity_3.cpp

clang

O3

43,314

4287

concept_complexity_1.cpp

gcc

O0

15,352

201

concept_complexity_2.cpp

gcc

O0

16,077

2244

concept_complexity_3.cpp

gcc

O0

18,091

4287

concept_complexity_1.cpp

gcc

O3

15,243

201

concept_complexity_2.cpp

gcc

O3

17,552

2244

concept_complexity_3.cpp

gcc

O3

18,51

4287

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

Заключение

В результате вышеописанных экспериментов мы можем сделать следующие выводы:

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

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

  • Время компиляции прямо пропорционально сложности концептов/constraint'ов.

Post Scriptum

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

Ну а во-вторых,мне быочень хотелосьувидеть, как ведут себя компиляторы с более сложными конструкциями.Если вы знаете/придумали подходящиепримеры, смелопишите о них в комментариях,ияс радостьюпроизведузамеры.

Подробнее..

Перевод Как 3D-печать меняет мир

14.11.2020 20:09:26 | Автор: admin

image


Новая эпоха технической революции


С каждым годом 3D-печать становится всё более массовой. По данным исследовательской группы CONTEXT, в 2015 году был отгружен 500-тысячный 3D-принтер, а к 2017 году продано около миллиона устройств. 3D-печать уже внедряется в качестве производственной технологии. Например, в 2016 году компания General Electric стала продавать авиационные двигатели с топливными форсунками, напечатанными на 3D-принтере. Ракеты Атлас-5 с деталями, напечатанными той же технологией, запустили в космос. Бренды Under Armour и New Balance пустили в продажу небольшие партии спортивной обуви, частично напечатанной на 3D-принтере, а компания Organovo запустила коммерческую биопечать тканей почек человека.


Пока что, это только фундамент. За всю историю человечества было множество технологических революций, каждая из которых проходила через три фазы. Первой идёт концептуализация, когда формируются видения и идеи, которые определяют дальнейший путь. Затем реализация, в течение которой кажущиеся ранее невозможными замыслы начинают частично реализовываться. И третья фаза массовая коммерциализация, когда предприятия осваивают производство и применение новой технологии.


И на какой же фазе находится 3D-печать? Применение 3D-принтера для превращения цифрового файла в физический объект уже получило широкое распространение. Например, в таких областях как инженерия, право, экономика, бизнес, география и искусство. Уже ведутся споры о последствиях обмена цифровыми объектами через интернет, чтобы тут же распечатать их на принтере (допустим огнестрельное оружие). Очевидно, что мы ещё далеки от того дня, когда персональные 3D-принтеры положат конец капитализму, передав производство в руки большинства. Тем не менее, не остаётся сомнений в том, что революция в области 3D-печати добралась до второй фазы реализации.


К сему моменту изобретено достаточно методов изготовления твёрдых объектов путём печати их множеством тонких последовательных слоев. На самом деле, наиболее распространённые технологии 3D-печати существуют уже несколько десятилетий.


Хотя технология продолжает развиваться, предположу, что до последней революционной фазы массовой коммерциализации остаётся около десяти лет. Пионеры 3D-печати уже используют её для изготовления самых разных вещей. Тем не менее, этот рынок по-прежнему остаётся нишевым и ограничен в коммерческом применении. В частности, это компании где занимаются мелкосерийным, штучным производством или товаров, которые невозможно изготовить традиционными методами.


Несмотря на вышеупомянутое, мы должны помнить, что десять лет назад ни один промышленный сектор не сообщал о продаже продуктов, полностью или частично изготовленных с помощью 3D-принтера. Поэтому, происходящее сейчас впечатляет. По мере развития методов 3D-печати и появления новых, а также того, как старые процессы становятся быстрее и дешевле, стоит ожидать, что 3D-печать приблизиться к фазе массовой коммерциализации в конце 2020-х или начале 2030-х годов. Новаторы этой области планируют воспользоваться преимуществами технологии задолго до этого.


Технология 3D-печати


И как же устроена 3D-печать? В значительной степени, она является эволюцией 2D-печати, уже используемой повсеместно в офисах и домах.


Большинство из нас знакомы со струйными или лазерными принтерами, которые позволяют печатать документы или фотографии. Они создают их, управляя нанесением чернил или тонера на поверхность листа бумаги. Подобным образом и 3D-принтеры производят объекты, контролируя размещение и адгезию последовательных слоёв строительного материала в трёхмерном пространстве. По этой причине 3D-печать также известна, как аддитивное производство слоёв (ALM Additive Layer Manufacturing) или аддитивное производство (АП или AM Additive Manufacturing).


Чтобы напечатать объект на таком принтере, потребуется цифровая модель на компьютере. Её можно создать с помощью приложения для автоматизированного проектирования (САПР) или другого ПО под трёхмерное моделирование. Также, цифровая модель может быть захвачена путём сканирования реального объекта 3D-сканером и обработкой с помощью CAD или других программ.


Затем модель необходимо пропустить через ещё одну программу для нарезки, которая разделит цифровой объект на множество слоёв поперечного сечения обычно толщиной около 0,1 мм. Эти цифровые ленты отправляются на 3D-принтер, который изготавливает их одну поверх другой, пока не будет сформирован реальный предмет.


image
3D-модель в Cura популярной программе для нарезки с открытым исходным кодом


image
Та же модель, которую печатает настольный 3D-принтер Ultimaker


image
Готовая игрушка


То, как 3D-принтер вырисовывает объект по одному слою за раз, зависит от технологии, на которой он построен. Существует множество методов 3D-печати и их можно разделить на 4 категории.


  • К первой категории относятся принтеры, которые создают объекты путём экструзии расплавленного полужидкого материала из сопла печатающей головки. Чаще всего это термопластик, который быстро затвердевает, покинув печатающую головку. Другие 3D-принтеры, основанные на экструзии, производят объекты, выводя расплавленный металл или шоколадную глазурь (для печати кулинарных творений). Есть также принтеры, которые используют бетон, керамическую пасту или глину.


  • Вторая категория 3D-принтеров создаёт слои объектов путём выборочного затвердевания жидкой смолы, известной как фотополимер, застывающий при воздействии лазера или другого источника света. Некоторые из таких машин создают слои объектов внутри резервуара с жидкостью. А другие выпускают слой смолы из печатающей головки, и используют ультрафиолет, чтобы закрепить его перед нанесением следующего слоя. Есть приборы, которые смешивают несколько разных фотополимеров в одном задании на печать, что позволяет им выводить цветные объекты, сделанные из нескольких материалов. В частности, один из таких принтеров J750 от Stratasys предлагает палитру из 360 тысяч оттенков и может изготавливать объекты из смеси различных материалов.


  • Третья и самая распространённая категория оборудования создаёт слои, выборочно склеивая гранулы очень тонкого порошка. Такое связывание гранулированных материалов достигается путём нанесения клея на слои порошка или плавлением гранул лазером или другим источником тепла. Существует множество видов порошковой адгезии на основе различных материалов. К ним относятся нейлон, воск, бронза, нержавеющая сталь, кобальт-хром и титан.


  • Последняя категория 3D-принтеров построена на ламинировании. Последовательные слои вырезанной бумаги, металла или пластика склеиваются, образуя твёрдый объект. Если в качестве строительного материала используются листы бумаги они разрезаются лезвием или лазером, затем склеиваются. На них можно распылять краску в процессе печати для создания недорогих полноцветных трёхмерных объектов.



Рынок и применение


3D-печать используется для создания прототипов, изготовления пресс-форм, прямого цифрового и индивидуального производств. Поставщики оборудования, программного обеспечения и материалов для 3D-печати уже обслуживают потребности различных секторов рынка. И сейчас мы рассмотрим эти области применения, чтобы понять, за счёт чего развивается технология трёхмерной печати.


Быстрое прототипирование


Чаще всего 3D-принтеры применяются для быстрого прототипирования (RP Rapid Prototyping). К этому относятся концепты и функциональные прототипы. Концепты представляют собой простые, нефункциональные черновики дизайна продукта (например, бутылка без съёмной крышки) и предназначены для того, чтобы художники могли воссоздать свои идеи в физическом формате. Функциональные прототипы напротив более сложны и позволяют оценить форму, соответствие и функции каждой части продукта перед тем, как пустить его в производство.


Функциональные прототипы и концепты создавались ещё до появления 3D-принтеров с использованием трудоёмких методов и инструментов. Поэтому на их производство нередко уходят много дней, недель или даже месяцев, а стоимость составляет тысячи или десятки тысяч долларов. 3D-принтеры могут создавать концепты и функциональные прототипы за несколько дней или даже часов, и за небольшую часть от стоимости традиционными способами изготовления. К примерам из этой отрасли можно отнести концепты автомобилей для Формулы-1.


Помимо экономии времени и денег, печать прототипов позволяет выводить на рынок улучшенные продукты, поскольку дизайн обычно проходит через множество итераций. Например, производитель термосов Thermos использует 3D-принтеры компании Stratasys для изготовления прототипов за часы, а не дни, и за пятую часть стоимости производства от внешнего поставщика. Поскольку дизайнеры теперь могут создавать столько прототипов, сколько потребуется, компания смогла доработать до совершенства такие характеристики продукта, как крепление крышки и удобство разливки.


Технология 3D-печати в цвете из различных материалов и металлов продолжает развиваться, поэтому ассортимент и качество продуктов, включая их компоненты, которые можно быстро прототипировать, продолжают увеличиваться. Так компания Nano Dimension продемонстрировала настольный 3D-принтер DragonFly 2020, который может изготавливать функциональные прототипы печатных плат. Это оборудование использует струйную технологию для вывода высокопроводящих наночернил и может производить многослойные платы, включая все соединения между слоями. В то время, когда многие компании ждут дни или недели, чтобы получить прототип платы от внешнего поставщика, аппарат напечатает её за считанные часы.


image


Пресс-формы и другие инструменты производства


Помимо прототипов, 3D-принтеры используются для изготовления пресс-форм и других приспособлений для производственного оборудования. Пресс-форма нужна для того, чтобы отливать в ней металлы или пластмассы. Как и прототипы, пресс-формы традиционно изготавливались вручную. Поэтому применение 3D-принтеров поможет сэкономить время и деньги крупным производителям. Например, используя принтеры Fortus компании Stratasys, автомобильный гигант Volvo Trucks из Лиона во Франции сократил время, необходимое для изготовления некоторых комплектующих двигателей с 36 дней до 2.


В августе 2016 года американская Oak Ridge National Laboratory напечатала на 3D-принтере инструмент для торцовки и сверления 5,34 x 1,34 x 0,46 м для компании Boeing. Он применяется при строительстве пассажирских самолётов, и был напечатан из армированного углеродным волокном пластика примерно за 30 часов. Раньше изготовление такой детали заняло бы три месяца. Как объяснил Лео Кристодулу из Boeing: Инструменты аддитивного производства, такие как инструмент для триммирования крыла: сэкономят энергию, время, рабочую силу и производственные затраты. Также они являются частью нашей стратегии по применению технологии 3D-печати в производственных областях.


Ещё одно многообещающее применение производство пресс-форм, используемых для литья металлов. 3D-принтеры способны изготавливать требуемые формы, а также любые дополнительные стержни, необходимые для размещения внутри них. Процесс осуществляется путём нанесения тонких слоёв формовочного песка, которые скрепляются связующим веществом. Полученные в результате 3D-распечатка формы отправляется в литейный цех, где в неё заливают расплавленный металл для получения готового изделия.


ExOne одна из компаний, специализирующихся на производстве 3D-принтеров для аддитивного производства при помощи литейного песка. Как утверждает компания, с помощью 3D-печати форм и стержней из литейного песка производители могут не только сэкономить время и снизить затраты, но также повысить точность и отливать более сложные детали. Это связано с тем, что формам и стержням, напечатанным на 3D-принтере, не требуется постобработка, которая могла нанести им повреждения.


image
Сердечник, отлитый форме, которая изготовлена на 3D-принтере ExOne


3D-принтеры также можно использовать для изготовления пресс-форм, которые нужны для литья пластмассовых деталей под давлением. Такие формы обычно стоят десятки тысяч долларов и традиционно изготавливаются из алюминия. Технически, 3D-принтер уже может изготавливать алюминиевые формы для литья под давлением с помощью металлического порошка. Однако, в настоящее время принтеры изготавливают такие формы из смолы при помощи фотополимеризации. Формы из пластмассы не такие износостойкие, как их алюминиевые аналоги. Однако, они дешевле, быстрее производятся и их можно использовать для изготовления до 200 пластиковых деталей, прежде чем потребуется замена.


Компания Bi-Link, базирующаяся в Блумингдейле штата Иллинойс, занимается 3D-печатью малотиражных пресс-форм для литья под давлением. Она изготавливает детали для производителей электроники и медицинского оборудования по всему миру. Принтер ProJet 3500 HD Max от 3D Systems создаёт форму за часы, вместо недель. Как отметил директор по исследованиям и разработкам Франк Зиберна: Клиенты в восторге от этой услуги. Раньше приходилось ждать две-три недели, чтобы получить только инструменты, не говоря уже о тестовых деталях. С помощью ProJet 3500 HD Max можно изготавливать для одного заказчика четыре различных конструкции в течение шести дней, отправив ему 10-12 деталей для каждой итерации за ночь.


Некоторые компании занимаются созданием машин, способных печатать объекты из воска (или его заменителей), чтобы создавать формы для литья по выплавляемым моделям. Восковой объект печатают на 3D-принтере, затем вокруг него формируют форму из такого материала, как гипс. После форма нагревается, в результате чего воск выгорает и стекает. Затем в форму заливают расплавленный металл или другой жидкий материал для создания готового изделия. Применение 3D-принтеров для создания восковых моделей довольно распространено в производстве ювелирных изделий и других отраслях, специализирующихся на сложных и дорогостоящих предметах. Как и пресс-формы для литья под давлением, восковые образцы являются расходным материалом, поскольку процесс создания готового изделия приводит к их разрушению.


Прямое цифровое производство


На нескольких нишевых рынках, 3D-принтеры уже используются для производства готовых промышленных компонентов и даже потребительских товаров. Такая разработка именуется как прямое цифровое производство (DDM Direct Digital Manufacturing) и приобретает всё большую популярность, например, в авиации. Airbus и Boeing устанавливают десятки тысяч компонентов своих самолётов, напечатанных на 3D-принтере.


К другим отраслям DDM относятся автомобилестроение, медицина, производство ювелирных изделий и обуви. Одним из ведущих пионеров считается Nike. По словам главного операционного директора Эрика Спранка, компания сделала ряд открытий в области дизайна и производства с помощью 3D-печати, которые позволят создавать совершенно новую индивидуальную систему амортизации обуви. С этой целью Nike строит Центр Создания Передовых Продуктов (Advanced Product Creation Center) площадью около 11-ти тысяч квадратных метров для размещения 3D-печати и других технологий проектирования и производства.


image


Вполне возможно, что в будущем с помощью 3D-принтера будет изготавливаться всё что угодно, включая даже человеческие органы. Наиболее заметно это в стоматологии: восковые модели, ортодонтические аппликации, примерки, хирургические шаблоны и модели виниров теперь печатаются на 3D-принтере.


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


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


Индивидуальное производство


Параллельно с ростом промышленной 3D-печати наблюдается рост индивидуального производства. Это все ситуации, когда предприниматель печатает на 3D-принтере собственные вещи, минуя запуск производства на удалённой фабрике. На рынке уже есть несколько сотен профессиональных 3D-принтеров по цене от 230 долларов.


В дополнение к растущему количеству персональных машин, растёт количество бесплатных и платных трёхмерных моделей, которые можно загрузить для распечатки. На ресурсе Thingiverse размещено более миллиона бесплатных моделей некоторые из них можно адаптировать под требования пользователя. Вполне возможно, что предоставление такого контента станет фундаментом для массового персонального производства, поскольку устранит необходимость в творческих и инженерных навыках.


В настоящее время персональные и профессиональные 3D-принтеры ограничены в возможностях применением термопластика или композитов, а также фотополимерных смол. Поэтому ассортимент и качество изделий, которые можно изготовить на таком оборудовании, остаются низкими. При этом, всё большее количество облачных сервисов 3D-печати, таких как Shapeways и i.materialise, позволяют любому загружать 3D-объект, который будет распечатан на промышленном оборудовании. Скорее всего, именно доступ к такой услуге а не продажа персональных 3D-принтеров станет движущей силой для революции индивидуального производства в течение следующих пяти-десяти лет.


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


В 2014 году IBM Institute for Business Value опубликовал отчёт, в котором выделены четыре варианта будущего для индивидуального производства. И сейчас мы кратко с ним ознакомимся.


  • Двумя неизвестными является скорость, с которой будет развиваться технология 3D-печати, и готовность потребителей принять индивидуальное производство. Если технологии будут совершенствоваться медленно, а потребители не станут применять 3D-печать в домашних условиях, тогда мы увидим тихую революцию с постепенными изменениями.


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


  • Ещё один вариант: технология 3D-печати совершит рывок, но потребители оставят её без внимания, тогда такая печать станет основной технологией в промышленном производстве, и не окажет большого влияния на потребительский рынок.


  • И последний ход событий: 3D-печать быстро развивается, а потребители её активно используют, тогда мы станем свидетелями переосмысления потребления. Это означает появление крупных и мелких торговцев, предлагающих продукты, напечатанные на 3D-принтере по вашему запросу. Также появится множество людей, печатающих в своих домах, гаражах, на кухнях или в офисах и ангарах.



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


Развитие индустрии 3D-печати


Существуют различные сегменты рынка 3D-печати, и находятся они на разных стадиях развития. Самые первые 3D-принтеры стали изготавливать прототипы в конце 1980-х годов, а использование печати для создания пресс-форм началось только через несколько лет после этого. Задолго до начала 2000-х появились первые готовые продукты и произведения искусства, распечатанные с помощью этой технологии. Наконец, изготовление на заказ стало возможным только в 2007 году с появлением первых 3D-принтеров с открытым исходным кодом, которые частные лица могли себе позволить.


Я считаю, что половина всех прототипов станет изготавливаться на 3D-принтере уже к 2025 году. Однако, трёхмерная печать не единственная технология быстрого прототипирования. Есть случаи, когда традиционные методы лучше подходят для производства прототипов. Невозможно представить, чтобы изобретатели перестали лепить вещи из глины, дерева, бумаги, металла, и всего остального, что есть в доступе на их кухнях, студиях, лабораториях, мастерских и сараях.


Что касается 3D-печати пресс-форм и инструментов производства этот рынок в настоящее время отстаёт от быстрого прототипирования, но очень скоро станет основой аддитивного производства. Предполагаю, что для его насыщения потребуется минимум десятилетие. Поговорив с производителями промышленных 3D-принтеров я в этом убедился. В большинстве отраслей, 3D-печать пресс-форм и других инструментов представляет крупнейшую рыночную возможность.


В прямом цифровом производстве такое только начинает происходить, хотя в настоящее время, это очень нишевый вид деятельности. Однако, в ближайшие десять лет или около того многие отрасли, в первую очередь авиакосмическая промышленность, автомобильный сектор, здравоохранение, мода, обувь и дизайнерские товары, будут использовать 3D-печать в качестве одной из своих основных производственных технологий. Это позволит создавать совершенно новые виды продукции и привлечёт внимание СМИ. И даже в этом случае, через 10 или 20 лет подавляющее большинство объектов в нашей жизни по-прежнему будет производиться традиционными методами.


Точно так же, в течение многих десятилетий изготовление личных вещей будет составлять нишевый сегмент рынка как в индустрии 3D-печати, так и в общемировом производстве. В настоящее время, не более 10% доходов индустрии 3D-печати формируется за счёт продажи персональных принтеров. Многие такие машины продаются компаниям, а не частным лицам. Но это не означает, что продажа персонального оборудования для домашнего использования не представляет рыночных возможностей.


Можно утверждать, что домашнее производство не станет движущей силой революции 3D-печати и многие участники отрасли, с этим согласны. Тем не менее, буду ждать с нетерпением 3D-принтеров за 99 долларов, которые смогут изготавливать небольшие пластиковые предметы, на основе модели, отправленной с планшета или смартфона.


Изготовление новых продуктов новыми способами


Как и предшествовавшая интернет-революция, 3D-печать позволяет компаниям и частным лицам достигать ранее невозможного. И причина не только в создании прототипов и старых вещей новыми способами. Она делает это в соответствии с новыми бизнес-моделями. Давайте обозначим эти ключевые преимущества.


Разовое и мелкосерийное производство


При использовании традиционных методов, разовое и мелкосерийное производство стоит дорого, а зачастую и непомерно. Когда вещи печатаются на принтере, практически нет разницы в стоимости на единицу то есть не важно требуются 1, 100 или 1000 копий, поскольку нет затрат на инструменты и рабочих. Поэтому во многих ситуациях, когда требуется несколько сотен или меньше компонентов, 3D-печать станет наиболее экономичным способом. Именно по этой причине, 3D-печать так широко применяется в быстром прототипировании и находит всё большее применения при производстве пресс-форм и других инструментов.


Джей Лено, который увлекается коллекционированием автомобилей, уже пользуется 3D-печатью для разового производства. В качестве примера: когда на редком концептуальном автомобиле EcoJet потребовалось заменить некоторые сломанные вентиляционные отверстия, он обратился в 3D Systems. Компания отсканировала сломанные детали, отремонтировала их в цифровом виде с помощью программы CAD и отправила полученные данные поставщику услуг Quickparts. Там новые вентиляционные отверстия напечатали на 3D-принтере из лёгкого нейлонового материала с наполнителем из волокон под названием DuraForm HST. В результате были получены надёжные запасные части, у которых соотношение прочности и веса стало лучше, чем у оригинала.


3D-печать используют при изготовлении реквизита для телешоу, кино и театральных постановок. С помощью этой технологии SpaceX печатает камеры двигателя космического корабля Crew Dragon, а NASA напечатала около 70 деталей для марсохода.


Кастомизация и персонализация


Помимо упрощения мелкосерийного производства идентичных вещей, трёхмерная печать позволяет настраивать продукцию в соответствии со вкусами покупателя и его физическими потребностями. Например, компания Robot Bike Co. использует технологию, чтобы изготавливать раму горного велосипеда R160 под заказ. Она создаётся из углеродного волокна, проходящего между титановыми выступами, которые печатаются на 3D-принтерах Renishaw. На сайте Robotbike.co покупатель вводит свой рост, размер ног и размах рук, что позволяет получить раму индивидуально под себя.


Велосипед R160 отличный пример реального продукта, который сочетает в себе детали, напечатанные на 3D-принтере, с другими стандартными компонентами. Это позволяет предложить продукт в соответствии с индивидуальными запросами экономичным способом. Я уверен, что, со временем, многие компании осознают потенциал изделий на заказ путём 3D-печати определённых деталей.


Оптимизация дизайна и сборки


Ещё одно ключевое преимущество 3D-печати состоит в том, что она снимает ограничения традиционных методов производства. Хотя дизайнер может придумать любой дизайн продукта, но если его компоненты нельзя отлить в форму, обработать и собрать продукт никогда не появится на рынке. А в дивном новом мире 3D-печати можно создавать вещи, которые ранее было невозможно изготовить. Например, такой принтер может изготовить цепочку или ожерелье, состоящее из звеньев, которые не имеют разрывов и, следовательно, никогда не разойдутся.


Команда TransFIORmers, участвующая в соревнованиях по мотогонкам, использовала 3D-принтер Renishaw для печати из металла, чтобы изготовить новую подвеску оптимизированной конструкции. Первоначальный вариант вручную изготавливался из стали, и при этом для сборки требовалось двенадцать деталей, которые необходимо сваривать вместе. Но с помощью 3D-печати, команда смогла объединить конструкцию в единый титановый компонент, который не требовал сборки, что привело к снижению веса на 40% критически важной характеристики для гонок.


Используя пластмассовые или полимерные материалы, некоторые принтеры могут создавать рабочие, предварительно собранные, составные механизмы, такие как коробка передач. Традиционно, производство многокомпонентных изделий включает этап окончательной сборки. Но когда вещи напечатаны на 3D-принтере в этом нет необходимости.


Свободный доступ к рынку


Помимо улучшения характеристик продуктов, трёхмерная печать позволит гораздо большему количеству людей стать производителями. Это связано с тем, что стоимость прототипов и производственных инструментов больше не будет чрезмерно высокой, поэтому 3D-печать делает малотиражное производство всё более жизнеспособным. Но что важнее, доступность сервисов услуг 3D-печати позволит практически любому талантливому художнику или дизайнеру найти рынок для своих творений.


Сегодня, частному лицу или даже небольшой компании, очень сложно вывести продукт на рынок, не говоря уже о глобальном масштабе. Одно из немногих исключений это книгоиздание, где автор может создавать и распространять продукт, который печатается по запросу. Например, жители Великобритании могут заказать печатную книгу через Amazon и в течение восьми часов им доставят книгу, напечатанную на складе корпорации. Это нововведение позволяет авторам продавать книги без предварительной печати и распространения.


Аналогичным образом, 3D-печать позволяет отдельным дизайнерам выпускать продукты на рынок без вложений в оборудование и предварительно изготовленные копии. Например, более 8 тысяч дизайнеров уже открыли интернет-магазины на площадке поставщика услуг 3D-печати компании Shapeways. В качестве примера, рассмотрим магазин известного создателя ботов Кидмехано (Kidmechano). Его творением являются Modibot, которые представляют собой постоянно расширяющуюся линейку фигурок, напечатанных на 3D-принтере, с шарнирной конструкцией. Можно сравнить Modibot с Lego или Трансформерами.


image


Кидмехано использует платформу Shapeways для продажи более 400 различных фигурок и аксессуаров ModiBot, включая доспехи и оружие. Цены начинаются от нескольких долларов, и когда заказ сделан, Shapeways печатает всё, что требуется, отправляя готовый продукт покупателю, а Кидмехано его долю выручки.


Цифровое хранение и транспортировка


Помимо обеспечения возможности мелкосерийного производства, экономичности и демократизации доступа к рынку, 3D-печать упростит хранение цифровых объектов и их транспортировку. Это означает, что в будущем станет два варианта отправки посылки. Первый заключается в отправке физического товара курьером или по почте, а второй передачей цифрового файла через интернет для 3D-распечатки на месте получателем.


Многие регулярно публикуют тексты, фотографии и видео в интернете, а благодаря 3D-печати цифровые объекты скоро будут добавлены в социальные сети. Таким образом, делая возможным цифровое хранение и транспортировку, 3D-печать сделает с вещами то, что компьютеры и интернет уже сделали для хранения и передачи информации.


В некоторых отраслях хранилище цифровых объектов уже начинает приносить пользу. Например, большинству стоматологов традиционно приходилось хранить огромное количество гипсовых слепков, снятых с ротовой полости пациентов. Хотя они использовалось только один раз, не было возможности предсказать: потребуются ли они в будущем, что привело к архивам с коробками и шкафами, заваленным гипсовыми моделями. Но теперь стоматологи переходят на цифровые технологии: 3D-сканеры и 3D-принтеры заменяют альгинатные формы и гипсовое литье. Это позволяет сохранять оттиски ротовой полости пациента в цифровом виде, для будущей 3D-распечатки в случае необходимости.


image


Экономия материалов и последствия для экологии


Помимо вышеупомянутых возможностей, 3D-печать экономит материалы производителям, что особенно важно для устойчивого развития. Сегодня, фабрики начинают производство с блока металла или другого сырья, а затем режут его: обрабатывают токарным станком, напильником, сверлом или иным образом, чтобы сформировать окончательный продукт. Напротив, 3D-печать это аддитивная деятельность, которая берёт такое количество материала, из которого состоит готовое изделие. Поэтому, мы получаем значительную экономию сырья, если изготавливать вещи при помощи этой технологии.


Кроме того, продукты 3D-печати могут иметь внутреннюю структуру, оптимизированную под расход минимального количества материалов. К примеру, пластиковые или металлические детали, напечатанные на принтерах, могут изготавливаться с внутренними полостями или открытой решёткой чего почти невозможно добиться с использованием большинства традиционных технологий. Опять же, это приводит к экономии материалов, а также к созданию более лёгких деталей, которые, например, уменьшат потребление топлива самолётов и других транспортных средств.


3D-печать может оказаться краеугольным камнем будущего перехода к местному цифровому производству (LDM Local Digital Manufacturing). Сегодня большая часть производства осуществляется на заводах, удалённых от своих клиентов. Как следствие, на хранение и транспортировку уходят огромные количества нефти и других ресурсов. Учитывая сокращение запасов природных ресурсов и меры по борьбе с изменением климата в течение одного-двух десятилетий, такие способы перевозки и хранение могут оказаться невыполнимыми или культурно неприемлемыми. Таким образом, защита экологии может оказаться силой, стимулирующей массовое внедрение 3D-печати, чтобы способствовать изготовлению товаров на местных производствах.


Трудности можно преодолеть!


Как и любая новая технология, 3D-печать может иметь как негативные, так и позитивные последствия. К примеру, есть опасения, что дальнейшее её развитие сократит рабочие места. И это вполне вероятно для некоторых профессий. В особенности для тех, кто производит прототипы, пресс-формы и инструменты традиционными методами.


Вполне возможно, что занятость в странах, которые готовят продукцию на экспорт, станет сокращаться по мере освоения технологией местными производствами. В своём обращении О положении страны 2013 года президент Обама отметил 3D-печать, как технологию, способную произвести революцию во всём, что мы делаем, и таким образом вернуть рабочие места из Азии обратно в США. Другими словами, глобальные экономические последствия развития 3D-печати были признаны на правительственном уровне одной из крупнейших экономик мира.


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


Некоторые отрасли также могут выиграть от распространения 3D-печати. Не в последнюю очередь, логистический сектор уже осознаёт эти возможности. Например, в июле 2014 года, в публикации Почтовой Службы США отмечалось, что оператор услуг может получить огромную выгоду от распространения 3D-печати по причине ожидаемого увеличения доставок мелких посылок. В частности, прогнозировалось, что технология может привести к увеличению доходов местной службы доставки посылок на 486 миллионов долларов в год. Прогноз основывался на предположении, что большинство товаров, напечатанных на 3D-принтере, будут производиться в местных бюро обслуживания, откуда их нужно будет доставлять к домам людей.


Помимо воздействия на занятость, есть ещё две проблемы: нарушение прав интеллектуальной собственности и использование 3D-печати в преступных целях. Уже сейчас можно использовать бытовое оборудование для сканирования объекта, например модели Микки Мауса, а затем печати его пластиковой копии. Подобно тому влиянию, которое музыка в формате mp3 и интернет оказали на музыкальную индустрию, 3D-печать может повлиять на права интеллектуальной собственности.


Что ещё тревожнее, уже возможно напечатать огнестрельное оружие на 3D-принтере. В настоящее время, персональный 3D-принтер за 230 долларов способен изготовить только одноразовый пластиковый пистолет. Но когда появится доступная возможность печати из металла, у нас возникнут серьёзные проблемы.


image


Последнее минное поле, связанное с 3D-печатью и изготовлением личных вещей, это здоровье и безопасность. Сегодня почти все продукты, которые мы покупаем, соответствуют определённым стандартам и проходят испытания. При этом производители несут ответственность за любые несчастные случаи и травмы, которые могут возникнуть в результате выхода их из строя или неисправности. Но кто будет нести ответственность, если, например, ребёнок загрузит бесплатную игрушку с сайта, распечатает её и отдаст младшему а тот проглотит отломанный от неё кусок и задохнётся? Будет ли вина лежать на человеке, разработавшем объект; сайте, через который он был опубликован, производителе 3D-принтера, поставщика расходных материалов или на родителе, который это допустил? Сейчас нет ответа на этот вопрос. И довольно скоро, мы не сможем это игнорировать.


В мире первопроходцев


Революция 3D-печати, как и любая другая технологическая революция продукт действий, энергии и видения тех людей, которые достаточно храбры, чтобы её осуществить. За последние несколько лет мне посчастливилось взять интервью у многих пионеров 3D-печати. И поскольку моя цель захватить ваше воображение, а не сосредотачиваться на деталях и технических подробностях, поэтому я задал им фундаментальный вопрос: Почему вы выбрали именно эту технологию?.


Одним из первых, с кем я общался, стал Ансси Мустонен руководитель финской компании по 3D-печати и дизайну AMD-TEC. По мнению Ансси, 3D-печать позволяет предоставить клиентам качественный уровень обслуживания:


Мы живем в беспокойном мире, но благодаря этой технологии можно предоставить клиентам качественные услуги. Что касается прототипов: у меня нет времени программировать и отправлять заказы внешним поставщикам для получения деталей. 3D-печать не единственный способ изготовления, но она быстрее при создании сложных форм и конфигураций, чем традиционные методы.

Константин Иванов, соучредитель и генеральный директор 3DPrintus.ru, рассказал мне, как технология позволяет предлагать новые виды продуктов и услуг:


3D-печать предоставляет решения, которые находятся на пересечении производства и цифровых технологий интернета. Наши клиенты открыли для себя лёгкий способ создания и производства практически всего. Я уверен, что главное преимущество для них это возможность использовать простой интерфейс, чтобы получить свой продукт.

Гэри Миллер, управляющий директор сервиса услуг печати 3D Print Bureau в Великобритании, рассказал похожую историю, хотя и с осторожностью в прогнозах:


Мы используем 3D-печать, потому что это быстрее: сокращается время выполнения заказа и доступна практически любая геометрия! Я начинал с принтера Objet более десяти лет назад, тогда был всего один материал. Прошли годы, и теперь есть около 2 тысяч материалов для печати. Только представьте, где мы будем через десять лет! Правда, сколько бы сырья у вас ни было, нужно передать его в надёжные руки. Нужен опыт в своей отрасли, чтобы понять, где эта техногия подходит, а где только увеличит стоимость. Раньше, скептически относился к тому, что 3D-печать перейдет в производство, но, в первой половине 2016 года, мы наблюдали прогресс и увеличение заказов. Приятно наблюдать, как развивается 3D-печать и появляются новые материалы.

Один из самых интересных разговоров состоялся с Джоном Коббом, исполнительным вице-президентом по корпоративным вопросам гиганта 3D-печати Stratasys в США. Вскоре после начала разговора, Джон сосредоточился на потенциале технологии для изменения дизайна и распространения продукции:


В 3D-печати много внимания уделяется её адаптации к традиционным производственным процессам. Меняются основы дизайна, что позволяет изменить способ производства продуктов, а затем методы распространения. Представьте, что возникла проблема с водопроводом. Вы фотографируете это на смартфон и отправляете в Home Depot (американская торговая сеть по продаже инструментов для ремонта и стройматериалов). И уже через час или два собираете трубопровод заменив нестандартную деталь. Возможно, на это уйдёт ешё лет пять, но мы уже движемся в этом направлении.

Миранда Бастийнс, директор бельгийской службы 3D-печати i.materialise, сосредоточила внимание на новых рыночных возможностях с другой точки зрения:


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

Люси Бирд, основатель компании Feetz, также признает потенциал 3D-печати для создания продуктов с лучшей посадкой. Feetz это цифровой сапожник, который использует 3D-принтеры для изготовления обуви по индивидуальному заказу. Как сказала мне Люси:


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

image


Марк Сондерс директор Центра Глобальных Решений (Global Solutions Centres) компании Renishaw, производящей 3D-принтеры. Он также сосредоточился на возможностях, которые технология предлагает производителям:


Всё больше компаний стремятся использовать потенциал 3D-печати для улучшения характеристик продукции, делая её более эффективной и лучше адаптированной к применению. Уникальная возможность создавать сложные геометрические формы из высококачественных материалов открывает огромный потенциал для инноваций как в дизайне продуктов, так и в бизнес-моделях. Мы ожидаем, что аддитивное производство будет играть ключевую роль в дальнейшем развитии процессов и улучшении продуктов.

Наконец, Сильвен Премонт основатель магазинов 3D-принтеров iMakr и сайта My Mini Factory, посвящённого 3D-контенту, отметил, как технология раскрепощает воображение:


Доступность трёхмерной печати даст волю творчеству: мы сможем изобретать, проектировать и изготавливать практически всё в кратчайшие сроки и по невысокой цене. Также появится возможность загружать контент, готовый к печати и легко адаптируемый к собственным потребностям. Следующее поколение будет спрашивать своих родителей: а как вы раньше обходились без 3D-принтера?

Новый рубеж


Как видно из интервью, 3D-печать продолжает вызывать интерес среди её пионеров. И многие крупные производители, применяющие традиционные технологии, уже меняют направление в сторону этой технологии.


Никто не может предсказать будущее 3D-печати. Тем не менее, есть веские основания полагать, что технология окажет радикальное воздействие на многие производственные сектора. В настоящее время большинство 3D-принтеров всё ещё печатают прототипы. Но менее чем через десять лет это изменится. Вполне возможно, что в будущем, десятки миллионов людей станут летать на самолётах с печатными компонентами, стоматологические кабинеты станут оснащать оборудованием, напечатанном на 3D-принтере, и мы будем носить обувь с печатными деталями.




image


Это только первая глава из книги Кристофера Барнатта 3D Printing. Вот, о чём автор поведает в продолжении:


В оставшихся главах книги я намерен исследовать мир 3D-печати, основываясь на конкретных примерах, информацию о поставщиках, исследованиях, отчетах компаний, интервью и других источниках. Также выскажу собственные взгляды и мнение. Но главное предоставлю читателю достаточно информации, чтобы решить, является ли 3D-печать следующей промышленной революцией.


Книгу можно приобрести как в цифровом, так и печатном варианте через сайт автора.
Также, на его ютуб-канале есть записи с выставок TCT Show 2017-2019 годов, на которых представляют последние разработки в 3D-печати.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru