模板参数推导/变量模板:如何使它起作用?

时间:2019-01-23 17:26:17

标签: c++ templates argument-deduction

在将模板类包装到非模板类中时遇到问题;

我正在尝试使此代码起作用:

my_class.hpp

#ifndef MY_CLASS_HPP
#define MY_CLASS_HPP

#include <vector>
#include <iostream>

class VectorPrinter {

private:

  template<class value_type>
  static std::vector<value_type> vec;

public:

  template<class value_type>
  VectorPrinter(const std::vector<value_type>& vec_)
  {
    vec = vec_
    for (std::size_t i = 0; i<vec.size(); ++i)
      std::cout << vec[i] << std::endl;
  }

};

#endif /* MY_CLASS_HPP */

main.cpp

#include "my_class.hpp"
#include <string>

int main() {

std::vector<int> v1{1, 2, 3, 4, 5};
std::vector<std::string> v2{"Hello", "world", "!"};
std::vector<double> v3{2.5, 7.3, -5.1};

VectorPrinter vp1(v1);
VectorPrinter vp2(v2);
VectorPrinter vp3(v3);

return 0;

}

在尝试编译时收到以下错误消息(我尝试了-std = c ++ 11,-std = c ++ 14,-std = c ++ 17:没什么区别;从g ++切换到++都没有区别lang):

./my_class.hpp:19:5: error: cannot refer to variable template 'vec' without a template argument list

现在:我的目标是规避将VectorPrinter定义为模板类,或者在VectorPrinter不能为非模板的情况下避免指定模板参数;所以我的问题就在变量模板或模板参数推导的范围之内。

这只是对我的论文项目的测试;最后,我需要实现的是能够为RNG定义模板库,并将这些类封装在执行Direct Simulation Monte Carlo的更复杂的类中。所以,最后我想要的是这样的东西:

template <class engineType>
class RngObject {
   // ...
};
class Ensemble {
   private:
      template<class engineType> RngObject<engineType> rng;
   // ...
};

必须定义将RNG封装为模板的每个类,这很无聊。此外,还要求我在现阶段避免使用动态时间多态性。

我希望有人能给我一些有用的建议。 谢谢

2 个答案:

答案 0 :(得分:3)

错误消息清楚地说明了您必须执行的操作:为vec指定模板参数。

  template<class value_type>
  VectorPrinter(const std::vector<value_type>& vec_)
  {
    // Using a reference here so we don't have to type all this again and again.
    auto& v = vec<value_type>;
    v = vec_;
    for (std::size_t i = 0; i < v.size(); ++i)
      std::cout << v[i] << std::endl;
  }

您还必须提供变量模板的定义:

template<class value_type>
std::vector<value_type> VectorPrinter::vec;

这应该可以满足您的要求:https://godbolt.org/z/gVFvFw
(对于您的用例而言,这是否是一个好的设计是另一个问题)。

答案 1 :(得分:1)

我对您的正确做法存有疑问;您不得不以这种方式使用静态成员,但是现在所有实例都将争夺该单个公共成员(当然,只有所有使用相同模板类型的实例)。这可能导致具有相同模板类型的对象之间发生竞争,尤其是在多线程环境中。

真正的模板类将允许具有非静态成员,这可能更安全,因此更可取。

如果选择模板变量只是为了不必在对象创建时重复模板参数,那么有个好消息:从C ++ 17开始,您可以让deduce类来自构造函数的模板参数。因此,如果您将您的课程设为模板:

template<class value_type>
class VectorPrinter { /* ... */ };

您仍然可以定义对象,而无需指定模板参数:

VectorPrinter vp1(v1); // fine with above template, too - since C++17

但不要依赖静态成员。

但是,如果您想将多个不同类型的VectorPrinter(模板版本)放入一个公共容器中,则需要引入一个公共基类。因此,在这种情况下,您可以选择:没有静态变量(特别是:没有变化的数量),而是多态性,或者相反。我有明确的个人喜好(并不意味着我会拒绝其他方法,如果在特定情况下证明是更好的话),但是您必须权衡一下自己……