繁体   English   中英

获取具有通用返回类型的函数

[英]Get function with generic return 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:
};

不幸的是,我不知道如何实现get函数。

一种解决方法是将名称声明为integer s而不是string s,并根据std::get使用实现,但是这里没有此选择: get的输入类型必须是字符串。

有人知道吗?

首先要记住,你不能直接做你想做的事情。 C ++是一种强类型的语言,因此必须编译时知道函数结果的类型。 因此,当然,如果在运行时知道传递给getter的字符串,则您将无法在编译时分派函数以让编译器推断出适当的结果类型。 但是,当您接受需要擦除类型以删除getter结果类型时,可以使用boost::variant处理问题。 C ++ 14示例(使用boost,因为c ++ 17变体应该在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;
}

[现场演示]

我确信您将能够优化代码(例如,使用移动语义/完美转发等)。 这只是向您展示如何开始实施。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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