Reputation: 3001
How can I place a reference to a templated class object inside a different (templated, although I'm not sure that's relevant) class?
Currently I have (simplified):
template <typename T, size_t D>
class Field
{
public:
template <size_t meshDim>
Field(const Mesh<meshDim>& mesh, const std::string &fileName):
fileName_(fileName),
meshDim_(meshDim),
mesh_(mesh) // <- this also doesn't compile,
// although I think it would if I had a data member named
// mesh_ that compiled
{
for (unsigned int d=0; d<D; d++) {
field_[d].reserve(mesh.numCells());
}
}
private:
std::vector<T> field_[D];
std::string fileName_;
const size_t meshDim_;
template<size_t meshDim>
const Mesh<meshDim> &mesh_; // <- This doesn't compile
};
This hits a compile-time error: data member 'mesh_' cannot be a member template
. This link about variable templates makes me think what I'm trying to do (or at least, something similar to what I'm trying to do) should be possible with c++14
, but probably not with c++11
.
If I remove the template<size_t meshDim>
line before the const Mesh<meshDim> &mesh_;
line (removing the template arguments also, to avoid undefined meshDim
), then I'm told that that I'm making invalid use of template-name 'Mesh' without an argument list
, which makes sense.
If I leave in the <>
, but without an argument (not that I expected this to work, but trying anything), I get wrong number of template arguments (0, should be 1)
.
Is this possible? Do I need to make some/all parts of some/all thing(s) static
or perhaps constexpr
?
In principle, there should be only one Mesh
object, and I'm ok with trying to make it a constexpr
constructor, since the parameters it needs could be #define
d by the build-system, if needed.
Upvotes: 2
Views: 230
Reputation: 443
The page you refer to says they can only be static data members.
Removing the rtemplate declaration and inserting a number eg const Mesh<15> &mesh_; does compile so it does seem like the problem is with the template.
Also N3651 does not suggest that templates parameters can be used as template arguments for variable. ( Though that seems to be ambiguous. )
Upvotes: 0
Reputation: 16156
In your current code, your field classes behaviour is explicitly depended on the meshDim
. At least that's what your code is saying. So you need to parametrise it on the mesh dimension:
template< typename T, size_t D, size_t meshDim>
class Field {
// ...
Field(mesh<meshDim> & m);
// ...
mesh<meshDim> & mesh_;
};
If the behaviour of field isn't directly depending on the mesh size, e.g. it can take any mesh, then you need to give it a reference to a class that's not depending on the mesh size:
class IMesh {
virtual void doStuff(void) = 0; // your interface
// ...
};
template<size_t meshDim>
class Mesh : public IMesh { // vtable or similar means required now
// ...
};
template< typename T, size_t D>
class Field {
// ...
Field(IMesh &);
// ...
IMesh & mesh_; // Reference, so no slicing
};
Concerning variable templates: They won't solve your problem:
When used at class scope, variable template declares a static data member template. (Source)
... which makes sense, since if you could have variable templates for non static data members it would be impossible to calculate the size of an object at it's declaration, because then you couldn't know what instantiations will be made.
Upvotes: 5