Структурированные привязки для вашего собственного типа, который не является структурой или кортежем (через открытую функцию-член)

Я прохожу Траву Скаттера

Путешествие: к более мощному и простому программированию на C ++

Связывание структуры раздел

Чтобы понять концепцию, лучше всего написать программу, которую я пробовал, но получаю ошибку

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

#include<iostream>
#include<string>
using namespace std;

class foobar {
public:
foobar() { cout << "foobar::foobar()\n"; }
~foobar() { cout << "foobar::~foobar()\n"; }

foobar( const foobar &rhs )
{ cout << "foobar::foobar( const foobar & )\n"; }
void ival( int nval, string new_string ) { _ival = nval;s=new_string; }

private:
int _ival;
string s;
};

foobar f( int val,string new_string ) {
foobar local;
local.ival( val,new_string );
return local;
}

template<> struct tuple_element<0,foobar> { using type = int; };
template<> struct tuple_element<1,foobar> { using type = string; };// 2. Now add get<> support (using C++17, because why not; it’s better
// than =delete’ing the primary get<> template and adding specializations)
template<int I>
auto get(const foobar&x) {
if      constexpr(I == 0) return x._ival;//'_ival' is a private member of 'foobar'
else if constexpr(I == 1) return x.s;//'s' is a private member of 'foobar'
}int main(){
foobar ml = f( 1024,"hello" );
auto [ n, s] = f( 1024,"hello" );//Cannot decompose non-public member '_ival' o
return 0;
}

ошибка

if constexpr (I == 0) return x._ival; // ‘_ ival’ является приватным членом
из ‘foobar’

иначе если constexpr (I == 1) return x.s; // ‘s’ является приватным членом ‘foobar’

auto [n, s] = f (1024, «hello»); // Невозможно разложить на непубличный

Требуется помощь

1. Если кто-то может описать, что он на самом деле пытается сделать на этих линиях
(пожалуйста, обратитесь по ссылке)

// 2. Now add get<> support (using C++17, because why not; it’s better
// than =delete’ing the primary get<> template and adding specializations)
template<int I>
auto get(const S&) {
if      constexpr(I == 0) return x.i;
else if constexpr(I == 1) return string_view{x.c}; }
else if constexpr(I == 2) return x.d;
}

2. Любое предложение, как исправить ошибку для приведенного выше примера.

4

Решение

Исправление ошибок в примере Саттера

Я думаю, что это опечатка / сбой в блоге Херба Саттера: он должен был сделать этих членов публичными, или предоставить для них получателей, или сделать std::get() поработай с другом.

Кроме того, похоже, что Херб забыл поставить «х» в сигнатуре функции …

Объяснение функции get

Функция, которую вы цитируете, похожа на std::get() работает для кортежей. Если у меня есть

std::tuple<int, std::string> t;

затем

auto x { std::get<0>(t) }; // x is an integer
auto y { std::get<1>(t) }; // y is an std::string

и в примере Херб, он должен иметь ту же работу для S класс, то есть есть std::get<0>(s) вернуть первого члена s, std::get<1>(s) вернуть второго члена и т. д. Это необходимо, потому что в противном случае вы не можете использовать S для инициализации структурированного связывания.

«Магия» в реализации Хебра заключается в том, что он возвращает значения разных типов из разных точек своей функции. Эта «магия» является эффектом if constexpr, По сути, это означает, что компилятор игнорирует все, кроме синтаксиса нерелевантных ветвей. Таким образом, для I = 0функция:

auto get(const S&) {
if (true) return x.i;
/* else if constexpr(I == 1) return string_view{x.c};
else if constexpr(I == 2) return x.d;
*/
}

за I = 1 его

template<int I>
auto get(const S&) {
if      (false) {/* return x.i; */ ; }
else if (true) return string_view{x.c};
/* else if constexpr(I == 2) return x.d; */
}
}

и т. д. auto выбирает подходящий тип.

2

Другие решения

Здесь много проблем.

Во-первых, для того, чтобы претендовать на структурированные привязки, необходимо специализироваться tuple_size:

namespace std {
template <> struct tuple_size<foobar> : std::integral_constant<size_t, 2> { };
}

Далее ваши специализации tuple_element также должен быть в namespace std:

namespace std {
template <> struct tuple_size<foobar> : std::integral_constant<size_t, 2> { };

template <> struct tuple_element<0,foobar> { using type = int; };
template <> struct tuple_element<1,foobar> { using type = std::string; };
}

Далее ваш get должен быть объявлен как friend функция, если вы собираетесь получить доступ к закрытым членам, как обычно:

class foobar {
template <int I> friend auto get(foobar const& );
};

И, наконец, get() действительно лучше возвращать ссылки, иначе ваши привязки в конечном итоге будут делать удивительные вещи:

template<int I>
auto const& get(const foobar&x) {
if      constexpr(I == 0) return x._ival;
else if constexpr(I == 1) return x.s;
}

Вместо того, чтобы иметь дело с friendкорабль, проще сделать get() открытый член, а затем запишите три необходимые вам перегрузки:

class foobar {
public:
template <size_t I>
auto& get() & {
if constexpr (I == 0) return _ival;
else if constexpr (I == 1) return s;
}

template <size_t I>
auto const& get() const& {
if constexpr (I == 0) return _ival;
else if constexpr (I == 1) return s;
}

template <size_t I>
auto&& get() && {
if constexpr (I == 0) return std::move(_ival);
else if constexpr (I == 1) return std::move(s);
}
};

Также ival() как функция не имеет смысла. Ваш конструктор должен просто принимать аргументы.

4

По вопросам рекламы [email protected]