Pull to refresh

Comments 9

> Его экземпляр создать невозможно, но компилятор это не волнует. Он действует на основании того, что ему сказали мы
--------------------------------
На основании того, что ему сказал Стандарт, а в комитете не только лишь Вы.

Почему такой код не считается ошибкой?

Derived(Derived const& d) : Base<T>(d) {}

Зачем C++ позволяет написать в шаблоне код, который заведомо не может скомпилироваться при использовании шаблона?

Сам догадался. Потому что может быть специализация шаблона Base или Derived где конструктор определён иначе:

template<>
struct Base<int>
{
    Base() = default;
    Base(Base const &) = default;
};

Потому что SFINAE.

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

Компилятор пытается создать конструктор копированиятолько в момент его вызова. А если конструктор не вызывался бы нигде в коде, то ошибки компиляции не было бы.

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

Здесь накладывается ещё возможность частичной специализации. В общем случае конструктора копирования может не быть (он компилируется в некорректный код), но есть частная специализация для int где конструктор реализован иначе и валиден.

Иногда думаю, что наследование это лажа какая-то. И больше 3х в глубину поддерживать - целая заморочка, и фиг перепишешь при куче интерфейсов, а вот эти хитро сделанные моменты как в статье, это однажды станут как thy thine thee в англ, старыми, и ненужными, неудобными и знать будет мало людей. Может однажды забудут реализовать в каком-нибудь потом компиляторе. Ну потому что фигня вот это сидеть и додумывать что же там копируется или нет, это не потому, что мы тупые, а потому что язык должен быть простым и понятным во всех смыслах.

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

Особенности кривизны C++. Инстанцирование шаблонных классов в нём не приводит к немедленному инстанцированию их методов и проверки корректности оных, методы компилируется, только если вызываются. Кода вызывается std::is_copy_constructible, класс инстанцируется и вроде даже проверяется наличие конструктора копирования в нём, но его тело на корректность не проверяется, ибо не нужно.

Шаблоны тут вовсе не при чем. В C и C++ широко практикуется отделение объявления от реализации, и is_copy_constructible далеко не всегда может проверить, что именно делает copy constructor. Вот например без всяких шаблонов:

$ cat module.h
struct Base
{
    Base() = default;
    Base(Base const &) = delete;
};

struct Derived: public Base
{
    Derived() = default;
    Derived(Derived const&);
};

$ cat module.cpp
#include "module.h"

Derived::Derived(Derived const&) : Base() {}

$ cat main.cpp
#include <type_traits>
#include "module.h"

static_assert(std::is_copy_constructible_v<Derived>);

int main() {}

Как прикажете is_copy_constructible в main.cpp проверять, что именно делает конструктор копии, реализация которого находится в module.cpp? Что, если module.cpp существует только в виде какого-нибудь module.so?

Да, отделение объявления от реализации может дать тот же эффект. Просто для шаблонов кажется, что реализация вроде тут-же доступна, но это не так, ибо по факту она инстанцируется только по необходимости.

Sign up to leave a comment.

Articles