Вопрос по шаблонам

Помогите разобраться.

Читал статью на Хабре. Не понял откуда что берется в шаблонах. Попробовал поэкспериментировать — вопросов еще больше :(

Есть такая штука:

template<
    std::intmax_t Num,       //Числитель
    std::intmax_t Denom = 1  //Знаменатель
> class ratio;

Это вообще что? Судя по тому, что после class ratio отстутствуют фигурные скобки, это опережающая декларация класса. Т.е. ожидается, что где-то дальше будет полное определение класса. Правильно? Но далее этого определения класса вроде как нет, а сразу используется:

using Mm = std::ratio<1>; //Знаменатель == 1
using Inches = std::ratio<254, 10>;
using Metre = std::ratio<1000, 1>;

А Num и Denom где хранятся, если класс даже не то, что бы пустой, но и вообще неопределенный?

И дальше:

template<class _Ratio>
class Length
{
    double length_;
public:
    explicit Length(double length) : length_(length) { }
    double length() const { return length_; }
};

Вроде это шаблон класса, параметризованный типом _Ratio. Но в определении самого класса _Ratio вообще не используется. Что здесь вообще происходит?

И еще дальше:

Length<Mm> len1(127.0);
Length<Inches> len2(5.0);
Length<Mm> len3 = len1 + len2;

Непонятно что в итоге будет означать Length<Mm>. Вот ваще непонятно :(
В третьей строке используется перегруженный оператор +:

template<class _Ratio1, class _Ratio2>
Length<Mm> operator+(const Length<_Ratio1> &left, const Length<_Ratio2> &right)
{
    double len =
        left.length() / _Ratio1::den * _Ratio1::num +
        right.length() / _Ratio2::den * _Ratio2::num;
    return Length<Mm>((int)len);
}

Опять вопрос: откуда берутся _Ratio1::den и пр. и где они хранятся?

Попробовал сделать

#include <iostream>

using namespace std;

template<
    std::intmax_t Num,       //Числитель
    std::intmax_t Denom = 1  //Знаменатель
> class ratio;

// без этого доопределения вообще ругается на неопределенный тип ratio
template<std::intmax_t Num, std::intmax_t Denom>
class ratio {

};

ratio<1> rat;   // хотя это компилируется и без доопределения ratio

int main() {
    cout << "sizeof(ratio<1>) = " << sizeof(ratio<1>) << endl;
    cout << "sizeof(rat) = " << sizeof(rat) << endl;
}

Получил

sizeof(ratio<1>) = 1
sizeof(rat) = 1

wtf?!

Всё просто. Шаблоны — это этам компиляции.
Так что всё что касается шаблонов,
должно быть известно на этапе компиляции.
Компилятор также может производить множество
вычислений на этапе компиляции.
В Вашем случае так и происходит.
Всё что касается ratio вычисляется
компилятором на этапе компиляции.
Определение класса в данном коде не нужно.
Для определения ссылок и указателей
достаточно объявления класса.
А размер объекта такой, потому что
согласно стандарту размер объекта
«пустого» класса не может быть равен нулю.
Не компилируется потому что для sizeof
нужно определение, которого не было.

ratio<1> rat;

тоже не должно собираться.

ratio<1> &rat1;//Соберется
ratio<1> *rat2;//Соберется
using ratT1 = ratio<1>;//Соберется
typedef ratio<1> ratT2;//Соберется

Можете написать мне на email: croessmah(собаченка)cyberforum(точечка)ru

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

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

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.