简体   繁体   中英

Get function with generic return type

I try to implement a data structure that comprises multiple name-value pairs where values may differ in their type:

template< typename T >
struct name_value_pair
{
  std::string name;
  T           value;
};


template< typename... Ts >
class tuple_of_name_value_pairs
{
  public:
    /* type of value */ get_value( std::string n )
    {
      // return the value that the element in
      // _name_value_pairs with name "n" comprises
    }

  private:
    std::tuple<Ts...> _name_value_pairs:
};

Unfortunately, I have no idea how to implement the get function.

A workaround would be to state names as integer s instead of string s and use an implementation according to std::get but this no option here: the input type of get has to be a string.

Has anyone an idea?

Firstly have in mind you cannot do what you want directly. C++ is a strongly typed language so type of function result must be known at compile time . So of course if the string you pass to the getter is known at runtime you're not able to dispatch function at compile time to let compiler deduce appropriate result type. But when you accept that you need type-erasure to erase the getter result type you could make use of eg boost::variant to deal with your problem. C++14 example (using boost, since c++17 variant should be available in std):

#include <boost/variant.hpp>
#include <utility>
#include <iostream>
#include <tuple>

template< typename T >
struct name_value_pair
{
  using type = T;
  std::string name;
  T           value;
};

template <std::size_t N, class = std::make_index_sequence<N>>
struct getter;

template <std::size_t N, std::size_t... Is>
struct getter<N, std::index_sequence<Is...>> {
     template <class Val, class Res>
     void setRes(Val &val, Res &res, std::string &s) {
         if (val.name == s)
             res = val.value;
     }

     template <class Tup>
     auto operator()(Tup &tuple_vals, std::string &s) {
         boost::variant<typename std::tuple_element<Is, Tup>::type::type...> result;
         int helper[] = { (setRes(std::get<Is>(tuple_vals), result, s), 1)... };
         (void)helper;
         return result;
     }
};

template <std::size_t N, class = std::make_index_sequence<N>>
struct setter;

template <std::size_t N, std::size_t... Is>
struct setter<N, std::index_sequence<Is...>> {
     template <class Val, class SVal>
     std::enable_if_t<!std::is_same<SVal, typename Val::type>::value> setVal(Val &, std::string &, const SVal &) { }
     template <class Val>
     void setVal(Val &val, std::string &s, const typename Val::type &sval) { 
         if (val.name == s)
             val.value = sval;
     }

     template <class Tup, class Val>
     auto operator()(Tup &tuple_vals, std::string &s, const Val &val) {
         int helper[] = { (setVal(std::get<Is>(tuple_vals), s, val), 1)... };
         (void)helper;
     }
};

template <class T, class Res>
using typer = Res;

template< typename... Ts >
class tuple_of_name_value_pairs
{
  public:
    auto get_value( std::string n )
    {
       return getter<sizeof...(Ts)>{}(_name_value_pairs, n);
    }
    template <class T>
    void set_value( std::string n, const T& value) {
        setter<sizeof...(Ts)>{}(_name_value_pairs, n , value);
    }
    void set_names(typer<Ts, std::string>... names) {
        _name_value_pairs = std::make_tuple(name_value_pair<Ts>{names, Ts{}}...);
    }

  private:
    std::tuple<name_value_pair<Ts>...> _name_value_pairs;
};

int main() {
    tuple_of_name_value_pairs<int, float, double> t;
    t.set_names("abc", "def", "ghi");
    t.set_value("abc", 1);
    t.set_value("def", 4.5f);
    t.set_value("ghi", 5.0);

    std::cout << t.get_value("def") << std::endl;
}

[live demo]

I'm sure you'll be able to optimise the code (eg make use of move semantics/perfect forwarding, etc.). This is only to present you how to get your implementation started.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM