Строго говоря, типы — это конструкции времени компиляции в C ++.
Однако бывают случаи, когда некоторые постоянные характеристики времени выполнения объекта эффективно определяются типом времени выполнения.
Например, если имеется геометрический вектор, где из-за ограничений структуры измерение известно только во время выполнения (в противном случае я бы сделал измерение параметром шаблона), например, для чтения из файла.
Тот факт, что измерение является средой выполнения, не означает, что нужно уметь сравнивать, назначать или комбинировать векторы с различным измерением.
Если кто-то хочет внедрить эту логику в код, он должен ограничить кучу операций.
Это может быть сделано с помощью утверждений или броска, только во время выполнения.
Так, например, можно было бы реализовать это,
class vec{
std::vector<double> impl_;
public:
vec(std::size_t size) : impl_(size){}
bool operator==(vec const& other) const{
if(impl_.size() != other.impl_.size()) throw std::domain_error("cannot compare vectors of different size");
return std::equal(impl_.begin(), impl_.end(), other.impl_.begin());
}
bool operator<(vec const& other) const{
if(impl_.size() != other.impl_.size()) throw std::domain_error("cannot compare vectors of different size");
return impl_ < other.impl_;
}
vector& operator=(vector const& other){
if(impl_.size() != other.impl_.size()) throw std::domain_error("");
std::copy(other.impl_.begin(), other.impl_.end(), impl_.begin());
return *this;
}
};
vec
реализуется с точки зрения std::vector
и никогда не изменит размер после строительства.
Проблема в том, что в итоге пишется ограничение во всех функциях.
Мой вопрос: есть ли идиомы или средства, которые могут помочь с этим, ограничивая (во время выполнения) операции, выполняемые с несовместимыми объектами, и, в частности, помогая писать менее повторяющийся код.
int v1_dim = 4;
int v2_dim = 3;
vec v1(v1_dim); // v1 has (forever) dimension 4, 4 is essential to v1
vec v2(v2_dim); // v2 has (forever) dimension 3
v1 = v2; // this is a logic error, I can't prevent the compilation of this unfortunately; So I will at least do a runtime check
v1 == v2; // this is a logic error, runtime error
Обратите внимание, что я не могу использовать std::array<double, 4>
или же 3>
так как 4
а также 3
могут быть переменными времени выполнения.
Есть ли у этой концепции эффективных типов времени выполнения имя? Было ли это расследовано?
Другие примеры, где это может произойти:
1) Представьте, что у вас есть массивы NxN переменного размера и вы пытаетесь определить математическое сложение. N будет временем выполнения (и даже постоянным после построения), и нужно будет убедиться, что он не добавляет массивы разных размеров, также хотелось бы, чтобы любое несовместимое сравнение вызывало ошибку.
2) В более общем плане эта философская проблема может появиться в классе с постоянными членами. Это своего рода выдумка, но предположим, что кто-то вынужден иметь const
члены
struct employee{
std::string const Name; // Once the employee is created it won't change name
double salary;
employee& operator=(employee const& other);
};
можно ограничить это:
employee& employee::operator=(employee const& other){
if(Name != other.Name) throw std::domain_error("cannot change name");
salary = other.salary;
return *this;
}
Единственное автоматическое решение, которое я представляю, — это систематическая перегрузка некоторого оператора (например, operator=() const
) в типах членов, чтобы заставить это.
struct employee{
My_string const Name; // Once the employee is created it won't change name
double salary;
employee& operator=(employee const& other){
Name = other.Name; //simply
salary = other.salary;
}
};
но где каждый зависит (полагается) от специальных типов членов с, например:
My_string const& My_string::operator=(My_string const& other) const{
if(*this != other) // this is the "real" inequality (not the restricted one), probably it will be if(this->std::string::operator=(other)) if My_string is derived from std::string
throw std::domain_error("assignment to const doesn't preserve value");
return *this;
}
и позже, чтобы быть последовательным и систематическим, можно написать:
employee const& employee::operator=(employee const& other) const{
if(*this != other) throw std::domain_error("assignment to const doesn't preserve value");
return *this;
}
Задача ещё не решена.
Других решений пока нет …