【问题标题】:How to invoke non-default constructor for template class?如何为模板类调用非默认构造函数?
【发布时间】:2012-06-04 08:35:57
【问题描述】:

我有以下代码结构(ResourceParameter 是空类):

求解器.cpp

#include "Solver.h"
#include "ValueFunction.h"

using namespace std;

template<typename T>
Solver<T>::Solver(vector<vector<Resource> >& resources, const Parameter& params) : 
    states(resources.size()) {
    for (int i=0; i<resources.size(); i++) {
        states[i] = State<T>(resources[i], params);
    }
}

// Explicit class declaration
template class Solver<ValueFunction>;

求解器.h

#ifndef SOLVER_H_
#define SOLVER_H_

#include <vector>
#include "Resource.h"
#include "Parameter.h"
#include "State.h"

template<typename T>
class Solver {
    public:
        Solver(
            std::vector<std::vector<Resource> >& resources,
            const Parameter& params
        );
    private:
        std::vector<State<T> > states;
};

#endif /* SOLVER_H_ */

状态.cpp

#include "State.h"
#include "ValueFunction.h"

using namespace std;

template<typename T>
State<T>::State(vector<Resource>& _resources, const Parameter& params) : 
resources(_resources), valfuncs(_resources.size(), T(params)) {
}

template class State<ValueFunction>;

状态.h

#ifndef STATE_H_
#define STATE_H_

#include <vector>
#include "Parameter.h"
#include "Resource.h"

template<typename T>
class State {
public:
    State() {};
    State(std::vector<Resource>& _resources, const Parameter& params);
    ~State() {};
private:
    std::vector<Resource> resources;
    std::vector<T> valfuncs;
};

#endif /* STATE_H_ */

值函数.cpp

#include "ValueFunction.h"

ValueFunction::ValueFunction(const Parameter& _params) : params(_params) {
}

ValueFunction.h

#ifndef VALUEFUNCTION_H_
#define VALUEFUNCTION_H_

#include "Parameter.h"

class ValueFunction {
public:
    ValueFunction(const Parameter& _params);
private:
    const Parameter& params;
};

#endif /* VALUEFUNCTION_H_ */

通过以下调用:

#include "Solver.h"
#include "State.h"
#include "ValueFunction.h"
#include "Parameter.h"

using namespace std;

int main(int argc, char *argv[]) {
Parameter params;
    vector<vector<Resource> > resources(4);
    Solver<ValueFunction> sol(resources, params);
    return 0;
}

我收到以下错误:

Solver.cpp:18:16:   instantiated from here
ValueFunction.h:6:21: error: non-static reference member ‘const Parameter& ValueFunction::params’, can't use default assignment operator

如何正确调用ValueFunction 的非默认构造函数,或者是否有其他方法可以使用非默认构造函数(传递常量引用)初始化std::vector

更新

post 中解释了该错误。但是我的问题的解决方法并不完全清楚。有什么建议吗?

【问题讨论】:

  • 发生错误是因为我想在ValueFunction类中用_params初始化params(不知道为什么会导致错误)。
  • 您必须将模板类的定义放在头文件中。模板定义需要在实例化时可见。在你的情况下,它们不是,所以你的编译器很困惑。见this question。我将您的代码放在一个源文件中并编译。
  • @jrok 这不是实例化问题,据我所知,隐式实例化被编译器接受为显式实例化(参见here)。
  • 当我添加 user315052 建议的更改时,我的代码编译正常。没有必要将它们放在一个文件中吗?你读过关于隐式实例化的文章吗?

标签: c++ templates constructor


【解决方案1】:

您正在使用调用向量成员的默认构造函数的构造函数的形式初始化Solverstates。您可以将第二个参数传递给states 类型为State&lt;T&gt; 的向量构造函数,向量将使用复制构造函数以该参数作为源来初始化向量元素。 Solver 构造函数中的循环仍然可以在状态向量中提供您实际需要的值。

编译器生成的默认构造函数无法初始化引用。这是因为初始化对象是默认构造函数的工作,但是引用需要引用一些东西。正如您在声明没有初始化器的引用变量时遇到错误一样,默认构造函数也会遇到同样的问题。

int &r;      // this is an error
int i;
int &rr = i; // this is proper

使用向量构造函数的复制构造函数版本可以帮助您避免这个问题,因为复制构造函数使用它正在复制的对象的值来初始化引用。在这种初始化向量的形式中,states 中的每个元素都被设置为与第一个元素相同的值。

...
    : states(resources.size(), State<T>(resources[0], params))
...

也许更好的方法是使用向量本身的默认构造函数,并使用reservepush_back 向向量添加元素。这更好,因为它完全避免创建任何 State&lt;T&gt; 对象,直到它被实际添加到向量中。

...
    : states()
...
    states.reserve(resources.size());
    for (int i...) {
        states.push_back(State<T>(resources[i], params));
    }
...

第三种方法可以让您的原始代码按其编写的方式工作,即为ValueFunction 定义您自己的默认构造函数,将params 成员初始化为某些东西(可能是可怕的全局)。

class ValueFunction {
public:
    ValueFunction (); // define our own default constructor
    ...
};

const Parameter global_default_parameter;

ValueFunction::ValueFunction () : params(default_parameter) {}

【讨论】:

  • 有没有办法将整个资源向量传递给构造函数?比如向量states的第一个State应该用resources[0]初始化,第二个用resources[1]初始化等等?
  • @Reza,这将是浪费精力,因为您必须编写一个辅助函数来创建整个向量,然后在 states 上调用向量的复制构造函数,这将导致向量被创建再次。
  • 您的回答帮助解决了我的问题的一部分(正确使用 State 构造函数),但它无法解决 std::vector 在常量上调用复制构造函数的问题成员。因此,您的第二种方法不适用于我的问题。我的解决方法是类似的,你在最后一部分建议,但不要再使用const Parameter&amp;
  • @Reza,根据您在问题中描述问题的方式,我不确定为什么第二种方法对您不起作用,您能详细说明一下吗?
猜你喜欢
  • 2019-04-01
  • 2014-02-05
  • 1970-01-01
  • 2015-10-20
  • 2014-05-18
  • 2011-03-27
  • 2010-10-30
  • 1970-01-01
  • 2011-01-06
相关资源
最近更新 更多