шаблоны по квалификаторам this

ilnur.khuziev
ilnur.khuziev
struct SaveLoadableType {
    int a;
    int b;
    int c;

    template<class IoClass, trait Qualifier>
    void SaveLoad(IoClass& io) Qualifier {
        io.AddField(a);
        io.AddField(b);
        io.AddField(c);
    }
}

struct TObjStreamSaver {
    template<class T>
    AddField(const T& val) {
        cout << val << " ";
    }
}

struct TObjStreamLoader {
    template<class T>
    AddField(T& val) {
        cin >> val;
    }
}

int main() {
    SaveLoadableType object;

    {
        const auto& ref = object;
        TObjStreamSaver saver;
        ref.SaveLoad(saver); //called const specialization: void SaveLoadableType::SaveLoad(TObjStreamSaver & io) const
    }
    
    {
        auto& ref = object;
        TObjStreamLoader loader;
        ref.SaveLoad(loader); //called non-const specialization: void SaveLoadableType::SaveLoad(TObjStreamLoader& io) const
    }
}

 

Конечно, введение нового ключевого слова очень спорно. В качестве алтернативы я бы предложил

struct SaveLoadableType {
    int a;
    int b;
    int c;

    template<class IoClass, class SelfClass>
    void SaveLoad(IoClass& io) SelfClass {
        io.AddField(a);
        io.AddField(b);
        io.AddField(c);
    }
}

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

 

-3
рейтинг
8 комментариев
dmitriy@izvolov.ru
Действительно, иногда очень хочется иметь возможность пробрасывания (он же perfect forwarding) для *this, чтобы не реализовывать по три метода для класса:
method () &
method () const &
method () &&

Но в представленном виде мне предложение не нравится. Нужно как-то по-другому.
dmitriy@izvolov.ru
Andrey Davydov
dmitriy@izvolov.ru, у меня есть безумная идея расширить const так чтобы он мог применяться к expression'у аналогично noexcept, const без параметров эквивалентен const(true). Тогда, скажем, определение оператора [] у класса vector могло бы выглядеть так:

template<typename T, bool constness>
struct add_const_if;

template<typename T>
struct add_const_if<T, true> : std::add_const<T> {};

template<typename T>
struct add_const_if<T, false>
{
using type = T;
};

template<typename T>
class vector
{
template<bool constness>
typename add_const_if<T, constness>::type& operator[] (size_t) const(constness);
};

Естественно, шаблонный аргумент constness должен автоматически выводиться при вызове. Заметим, что необходимый механизм в компиляторе уже есть. Это хорошо видно если рассмотреть свободную функцию:
template<class Vec>
typename add_const_if<typename Vec::value_type, std::is_const_v<Vec>>::type & at(Vec &, size_t);

void foo(vector<int> & xs, vector<int> const & ys)
{
at(xs, 0); // Vec -> vector<int>
at(ys, 1); // Vec -> vector<int> const
};
работает уже сейчас, а значит, и для такой функции
template<class T, bool constness>
typename add_const_if<T, constness>::type & at(vector<T> const(constness) &, size_t);
вывод шаблонных аргументов возможен.
Andrey Davydov
dmitriy@izvolov.ru
Andrey Davydov,
По-прежнему сомнительно.
Во-первых, не упомянут вариант с `&&`.
Во-вторых, помимо `const` ещё есть `volatile`.
dmitriy@izvolov.ru
ilnur.khuziev
dmitriy@izvolov.ru, ну можно сделать и volatile(bool)
ilnur.khuziev
Andrey Davydov
dmitriy@izvolov.ru,
> Во-первых, не упомянут вариант с `&&`
Можете привести пример, когда было бы полезно сделать функцию шаблонной по ref qualifier'у?
> Во-вторых, помимо `const` ещё есть `volatile`
Аналогично, не могу придумать, когда может быть полезным метод шаблонный по volatile/non-volatile?
Andrey Davydov
Олег Ляттэ
Andrey Davydov, vector::operator[] вроде бы неплохой пример и для &&, и для volatile.

Пример для &&:
std::vector<std::string> f();
auto s = f()[0]; // move-initialize s from element 0

Пример для volatile:
void f(long& s); // 1
void f(volatile long& s); // 2

volatile std::vector<long> vec;
f(vec[0]); // calls 2
Олег Ляттэ
Andrey Davydov
Олег Ляттэ, что касается &&, то для того чтобы f()[0] имело тип string &&, надо чтобы в теле `vector::operator[] (size_t i) &&` было явно написано std::move(i-й элемент). Как Вы предлагаете сделать это если operator[] будет шаблонным?
Пример же с volatile, на мой взгляд, совершенно некорректен -- то что сам объект вектора является volatile никак не связано с волатильностью его элементов.
Andrey Davydov
Олег Ляттэ
Andrey Davydov, для возврата && можно использовать static_cast - эффект будет не хуже, чем от std::move. Нужно только вывести референс нужного вида.

Квалификатор volatile имеет то же поведение, что и const. Отличается только их смысловое действие. Не даром они в стандарте часто упоминаются вместе (cv-qualifiers). Если const vector добавляет const к выдаваемым референсам на элементы, то по логике volatile vector должен делать то же самое, т.е. распространять действие своих квалификаторов на элементы.
Олег Ляттэ
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).