Типы данных C ++ в шаблонах - PullRequest
0 голосов
/ 05 июня 2018

У меня есть вопрос о том, как правильно / правильно использовать шаблоны в C ++.

Допустим, у нас есть такой шаблонный класс:

template <typename T> class Foo
{
    public:
        T add(T n1, T n2);
};

template <typename T> T Foo<T>::add(T n1, T n2)
{
    return(n1 + n2);
}

Это будет работать очень хорошос основными типами данных, такими как int, double, float, char ... и т. д.

Foo <int> foo_int;
std::cout << std::to_string(foo_int.add(2, 5)) << std::endl;

Foo <double> foo_double;
std::cout << std::to_string(foo_double.add(2.2, 6.1)) << std::endl;

Foo <char> foo_char;
std::cout << std::to_string(foo_char.add('A', 'm')) << std::endl;

Но это не очень хорошо работает со сложными типами данных, такими как этот:

class Bar
{
    public:
        std::string bar;
};

Bar bar_1;
Bar bar_2;
Foo <Bar> foo_bar;

std::cout << std::to_string(foo_int.add(bar_1, bar_2)) << std::endl;   

Можно ли писать шаблоны, которые работают только с несколькими типами данных, или шаблоны следует использовать только в том случае, если они работают со всеми типами данных, такими как std :: vector.

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

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

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Прекрасно писать шаблоны, которые работают только с типами, которые поддерживают определенные операции.Фактически, обратное сделало бы написание любого шаблона подвигом героизма.

Первая ошибка - документация.Например, все стандартные алгоритмы из <algorithm> получают итераторы произвольных типов.Вы знаете, что они должны быть итераторами, потому что они названы и задокументированы таким образом.Быть итератором подразумевает, что экземпляр должен иметь возможность увеличиваться, сравниваться и разыменовываться как минимум (но некоторые алгоритмы требуют большего).Этот набор способностей известен как Iterator концепт , но это только документация.

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

  • Сложные ошибки с помощью static_assert.Вы пишете проверку во время компиляции для своей концепции, проверяете ее с помощью static_assert и останавливаете компиляцию, если она не удалась.

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

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

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

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

0 голосов
/ 05 июня 2018

Но это не очень хорошо будет работать со сложными типами данных, такими как этот:

Это потому, что Bar не предоставляет Bar::operator+(Bar, Bar) - если это так, он будет работать сваш шаблон.


Можно ли писать шаблоны, которые работают только с несколькими типами данных

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


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

Если вы хотите, чтобы ваш шаблон работал со всеми типами, которые соответствуют определенному интерфейсу, вы хотитеиспользовать концепции (доступно в C ++ 20, может быть эмулировано в C ++ 11).

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

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