当前位置: 首页 > 知识库问答 >
问题:

每个可变模板参数生成一个类成员

廖弘伟
2023-03-14

我有一个模板类,其中每个模板参数代表内部计算可以处理的一种类型的值。需要模板(而不是函数重载),因为值被作为::any传递,并且它们的类型在运行时之前不清楚。

为了正确地转换为正确的类型,我希望每个变量参数类型都有一个成员列表,类似于这样:

template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
    std::vector<T1> m_argumentsOfType1;
    std::vector<T2> m_argumentsOfType2; // ...
};

或者,我想将模板参数类型存储在一个列表中,以便对其进行RTTI处理(?)。但如何将它们保存在std::initializer\u列表成员中,我也不清楚。

谢谢你的帮助!

共有3个答案

西门鹏程
2023-03-14

这样做的一种方法,如πάντα所述-ῥεῖ'的注释是使用元组。他没有解释的(可能是为了救你自己)可能是这样的。

以下是一个例子:

using namespace std;

// define the abomination    
template<typename...Types>
struct thing
{
    thing(std::vector<Types>... args)
    : _x { std::move(args)... }
    {}

    void print()
    {
        do_print_vectors(std::index_sequence_for<Types...>());
    }

private:
    template<std::size_t... Is>
    void do_print_vectors(std::index_sequence<Is...>)
    {
        using swallow = int[];
        (void)swallow{0, (print_one(std::get<Is>(_x)), 0)...};
    }

    template<class Vector>
    void print_one(const Vector& v)
    {
        copy(begin(v), end(v), ostream_iterator<typename Vector::value_type>(cout, ","));
        cout << endl;
    }

private:
    tuple<std::vector<Types>...> _x;
};


// test it
BOOST_AUTO_TEST_CASE(play_tuples)
{
    thing<int, double, string> t {
        { 1, 2, 3, },
        { 1.1, 2.2, 3.3 },
        { "one"s, "two"s, "three"s }
    };

    t.print();
}

预期产出:

1,2,3,
1.1,2.2,3.3,
one,two,three,
邓卓
2023-03-14

不使用元组的另一种解决方案是使用CRTP创建类层次结构,其中每个基类都是以下类型之一的专用化:

#include <iostream>
#include <string>

template<class L, class... R> class My_class;

template<class L>
class My_class<L>
{
public:

protected:
  L get()
  {
    return val;
  }

  void set(const L new_val)
  {
    val = new_val;
  }

private:
  L val;
};

template<class L, class... R>
class My_class : public My_class<L>, public My_class<R...>
{
public:
  template<class T>
  T Get()
  {
    return this->My_class<T>::get();
  }

  template<class T>
  void Set(const T new_val)
  {
    this->My_class<T>::set(new_val);
  }
};

int main(int, char**)
{
  My_class<int, double, std::string> c;
  c.Set<int>(4);
  c.Set<double>(12.5);
  c.Set<std::string>("Hello World");

  std::cout << "int: " << c.Get<int>() << "\n";
  std::cout << "double: " << c.Get<double>() << "\n";
  std::cout << "string: " << c.Get<std::string>() << std::endl;

  return 0;
}
楚羽
2023-03-14

正如已经暗示的,最好的方法是使用元组:

template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
    std::tuple<std::vector<AcceptedTypes>...> vectors;
};

这是乘以“字段”的唯一方法,因为你不能神奇地让它拼出字段名称。另一个重要的事情可能是获得一些命名的访问权限。我猜你想实现的是拥有具有唯一类型的多个向量,所以你可以使用以下工具根据其值类型“搜索”正确的向量:

template <class T1, class T2>
struct SameType
{
    static const bool value = false;
};

template<class T>
struct SameType<T, T>
{
    static const bool value = true;
};

template <typename... Types>
class MyClass
{
     public:
     typedef std::tuple<vector<Types>...> vtype;
     vtype vectors;

     template<int N, typename T>
     struct VectorOfType: SameType<T,
        typename std::tuple_element<N, vtype>::type::value_type>
     { };

     template <int N, class T, class Tuple,
              bool Match = false> // this =false is only for clarity
     struct MatchingField
     {
         static vector<T>& get(Tuple& tp)
         {
             // The "non-matching" version
             return MatchingField<N+1, T, Tuple,
                    VectorOfType<N+1, T>::value>::get(tp);
         }
     };

     template <int N, class T, class Tuple>
     struct MatchingField<N, T, Tuple, true>
     {
        static vector<T>& get(Tuple& tp)
        {
            return std::get<N>(tp);
        }
     };

     template <typename T>
     vector<T>& access()
     {
         return MatchingField<0, T, vtype,
                VectorOfType<0, T>::value>::get(vectors);
     }
};

这里是测试用例,所以你可以尝试一下:

int main( int argc, char** argv )
{
    int twelf = 12.5;
    typedef reference_wrapper<int> rint;

    MyClass<float, rint> mc;
    vector<rint>& i = mc.access<rint>();

    i.push_back(twelf);

    mc.access<float>().push_back(10.5);

    cout << "Test:\n";
    cout << "floats: " << mc.access<float>()[0] << endl;
    cout << "ints: " << mc.access<rint>()[0] << endl;
    //mc.access<double>();

    return 0;
}

如果您使用的任何类型不在您所传递的用于专门化MyClass的类型列表中(请参阅此注释掉的access for double),您将得到一个编译错误,不太可读,但gcc至少指出了导致问题的正确位置,并且至少这样一条错误消息指出了问题的正确原因-例如,如果你想做mc。通道

 error: ‘value’ is not a member of ‘MyClass<float, int>::VectorOfType<2, double>’
 类似资料:
  • 我想有一个可变的类模板来生成每种类型的一个方法,例如像下面这样的类模板: 将使方法

  • 我试图从一组可变的模板类(其中每个类都有一个非类型参数)中恢复非typename模板参数,以便在另一种类型中将它们用作整数序列。 下面的代码显示了我所拥有的。整数序列/成员序列是从元组中抄袭出来的。 和的类型是

  • 在C++11之前,类模板和函数模板只能含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。可变参数模板的加入使得C++11的功能变得更加强大,而由此也带来了许多神奇的用法。 可变参数模板 可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号...: template<ty

  • 完成了教程-历史 的学习之后, 我们来到 my-hello [仓库]里面,就是我们在 教程-克隆中 [克隆] 得到的。 在 Mercurial 开发实践中一个好的做法是把每个变更隔离在各自的仓库里。这样可以避免把不相关的代码混杂起来, 并且便于一个接一个的测试每一部分工作。我们现在就开始采用这一模式。 我们的目标很简单,让“hello, world”程序打印另外一行输出。 首先, 我们给这个小项目

  • 我有一个函数,它使用Boost进行base64编码。它有两个模板参数:一个用于输入的容器类型,另一个用于输出的容器类型。这允许您使用提供二进制数据,但可以返回。 这是代码: 用法示例: 这里有活样品 请注意,在上面的示例中,我仍然必须为输出容器提供模板参数,即使它与输入容器的类型相同。在这些场景中,我希望模板参数是可选的,而是使用由推导的类型。我不确定我可以执行什么变通或调整来获得这种界面,但很高

  • 我是新使用模板。作为标题,我有一个非模板类(Obj和ObjBase)和一个模板类pitem。我想让pItem::RefValue()访问obj中的私有成员。 我想下面的行得通: 它不: 错误C2248:“obj::GetValue”:无法访问类“obj”中声明的私有成员 注意:请参阅对正在编译的函数模板实例化“int PItem::GetValue(void)”的引用 编译器投诉: