Я прохожу Траву Скаттера
Путешествие: к более мощному и простому программированию на 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. Любое предложение, как исправить ошибку для приведенного выше примера.
Я думаю, что это опечатка / сбой в блоге Херба Саттера: он должен был сделать этих членов публичными, или предоставить для них получателей, или сделать std::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
выбирает подходящий тип.
Здесь много проблем.
Во-первых, для того, чтобы претендовать на структурированные привязки, необходимо специализироваться 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()
как функция не имеет смысла. Ваш конструктор должен просто принимать аргументы.