Что я делаю не так?
Как предполагает n.m., вы должны рассмотреть, что оператор запятой делает со следующим выражением
(ObjKey("key2"), ObjVal("test21"), (ObjKey("key3"), ObjVal("test31"), ObjVal("test32")), ObjVal("test22"))
Оператор запятой отбрасывает все значения, кроме последнего, поэтому выражение становится
(ObjVal("test22"))
А можно ли решить с помощью шаблонов?
Да, но лучшее, что я могу себе представить, это std::tuple
.
Я имею в виду ... если вы согласитесь, что get()
вызов станет
auto result = Builder::get(
ObjKey("key1"),
ObjVal("test1"),
std::make_tuple(ObjKey("key2"), ObjVal("test21"),
std::make_tuple(ObjKey("key3"), ObjVal("test31"),
ObjVal("test32")),
ObjVal("test22")),
ObjVal("test2"));
поэтому, добавив std::make_tuple
перед группировкой (
, вы можете добавить пару личных get()
для управления регистром кортежей.
Таким образом, переименовав getH()
(для «get helper») в частные версии get()
, управляющие кортежами версии getH()
можно записать следующим образом (решение C ++ 14, поскольку используется * 1030). * и std::make_index_sequence
; но если вам нужно решение C ++ 11, не сложно написать заменители C ++ 11)
template <std::size_t ... Is, typename ... Ts, typename ... As>
static void getH (std::string & rV, std::index_sequence<Is...> const &,
std::tuple<Ts...> const t, As ... as)
{
getH(rV.append(", "), std::get<Is>(t)...);
getH(rV, as...);
}
template <typename ... Ts, typename ... As>
static void getH (std::string & rV, std::tuple<ObjKey, Ts...> const t,
As ... as)
{ getH(rV, std::make_index_sequence<1u+sizeof...(Ts)>{}, t, as...); }
Версии ключа и значения управляются следующим образом
template <typename ... As>
static void getH (std::string & rV, ObjKey const & oK, As ... as)
{
getH(rV.append(1u, '{').append(oK.get()), as...);
rV.append(1u, '}');
}
template <typename ... As>
static void getH (std::string & rV, ObjVal const & oV, As ... as)
{ getH(rV.append(", ").append(oV.get()), as...); }
и, очевидно, наземный корпус
static void getH (std::string &)
{ }
Публичная get()
версия стала
template <typename ... As>
static std::string get (As ... as)
{
std::string resultValue;
getH(resultValue, as...);
return resultValue;
}
Обратите внимание, что я перевел управление запятой с ObjKey
и ObjVal
на getH()
и что я удалил семантику переадресации (вы никогда не использовали std::move
).
Ниже приведен полный пример C ++ 14
#include <tuple>
#include <iostream>
class Obj
{
public:
Obj() = delete;
Obj (std::string const & v0) : v{v0}
{ }
std::string const & get () const
{ return v; }
private:
std::string v;
};
struct ObjKey : public Obj
{ ObjKey (std::string const & v0) : Obj{v0} { } };
struct ObjVal : public Obj
{ ObjVal (std::string const & v0) : Obj{v0} { } };
class Builder
{
private:
template <std::size_t ... Is, typename ... Ts, typename ... As>
static void getH (std::string & rV, std::index_sequence<Is...> const &,
std::tuple<Ts...> const t, As ... as)
{
getH(rV.append(", "), std::get<Is>(t)...);
getH(rV, as...);
}
template <typename ... Ts, typename ... As>
static void getH (std::string & rV, std::tuple<ObjKey, Ts...> const t,
As ... as)
{ getH(rV, std::make_index_sequence<1u+sizeof...(Ts)>{}, t, as...); }
template <typename ... As>
static void getH (std::string & rV, ObjKey const & oK, As ... as)
{
getH(rV.append(1u, '{').append(oK.get()), as...);
rV.append(1u, '}');
}
template <typename ... As>
static void getH (std::string & rV, ObjVal const & oV, As ... as)
{ getH(rV.append(", ").append(oV.get()), as...); }
static void getH (std::string &)
{ }
public:
template <typename ... As>
static std::string get (As ... as)
{
std::string resultValue;
getH(resultValue, as...);
return resultValue;
}
};
int main()
{
auto result = Builder::get(
ObjKey("key1"),
ObjVal("test1"),
std::make_tuple(ObjKey("key2"), ObjVal("test21"),
std::make_tuple(ObjKey("key3"), ObjVal("test31"),
ObjVal("test32")),
ObjVal("test22")),
ObjVal("test2"));
std::cout << result << "\n";
}