Разделение внутренних и внешних конструкторов с одинаковым набором параметров - PullRequest
0 голосов
/ 14 февраля 2019

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

Мне нужны два конструктора: один внутренний и один внешний.Внешний конструктор должен выполнять проверку, а внутренний конструктор - нет.В остальном они имеют одинаковые параметры, единственное отличие - проверка, которая является главной проблемой.Проверка избегается по соображениям производительности.Ниже приведен пример макета.

#include <stdexcept>

template <int limit>
class ClippedValue;

template <int limit>
void check(ClippedValue<limit> v) {
    if (std::abs(v.value) > limit) {
        make_user_solve_P_eq_NP();
        throw std::range_error("Given value exceeds available range");
    }
}

template <int limit>
class ClippedValue {
public:  // external constructor
    constexpr ClippedValue(int a) : value(a) { check(*this); }
private:  // internal constructor
    constexpr ClippedValue(int a) : value(a) {}
public:  // members
    const int value;
public:  // friends
    template <int A, int B>
    friend constexpr ClippedValue<A + B> operator+ (ClippedValue<A> a, ClippedValue<B> b);
}

template <int A, int B>
constexpr ClippedValue<A + B> operator+ (ClippedValue<A> a, ClippedValue<B> b) {
    return a.value + b.value;
}

Выше не компилируется, два конструктора идентичны.

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Выше не компилируется, два конструктора идентичны.

Действительно.Поэтому различайте их.

enum class unchecked_t {};
constexpr ClippedValue(unchecked_t, int a) : value(a) {}

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

0 голосов
/ 14 февраля 2019

Как вы уже узнали, у вас не может быть двух конструкторов с одинаковым интерфейсом.

Вы можете добавить фиктивный аргумент ко второму конструктору, чтобы отличать его от первого.

template <int limit>
class ClippedValue
{
   public:

      // external constructor
      constexpr ClippedValue(int a) : value(a) { check(*this); }

   private:

      // A type that can be used only internally and by friends of the class.
      struct internal {};

      // internal constructor. An overload.
      // Use another argument, of type internal.
      constexpr ClippedValue(int a, internal) : value(a) {}

      ...
};
...