C++ class with template member variable
You got very close. I added a few bits because they're handy
class ParameterBase
{
public:
virtual ~ParameterBase() {}
template<class T> const T& get() const; //to be implimented after Parameter
template<class T, class U> void setValue(const U& rhs); //to be implimented after Parameter
};
template <typename T>
class Parameter : public ParameterBase
{
public:
Parameter(const T& rhs) :value(rhs) {}
const T& get() const {return value;}
void setValue(const T& rhs) {value=rhs;}
private:
T value;
};
//Here's the trick: dynamic_cast rather than virtual
template<class T> const T& ParameterBase::get() const
{ return dynamic_cast<const Parameter<T>&>(*this).get(); }
template<class T, class U> void ParameterBase::setValue(const U& rhs)
{ return dynamic_cast<Parameter<T>&>(*this).setValue(rhs); }
class Diagram
{
public:
std::vector<ParameterBase*> v;
int type;
};
Diagram can then do stuff like these:
Parameter<std::string> p1("Hello");
v.push_back(&p1);
std::cout << v[0]->get<std::string>(); //read the string
v[0]->set<std::string>("BANANA"); //set the string to something else
v[0]->get<int>(); //throws a std::bad_cast exception
It looks like your intent is to store resource-owning pointers in the vector. If so, be careful to make Diagram
have the correct destructor, and make it non-copy-constructable, and non-copy-assignable.
Templated member variables in C++
This is possible in the library by combining existing facilities.
The simplest implementation would be
std::unordered_map<std::type_index, std::any>
This is mildly inefficient since it stores each std::type_index
object twice (once in the key and once inside each std::any
), so a std::unordered_set<std::any>
with custom transparent hash and comparator would be more efficient; this would be more work though.
Example.
As you say, the user of the library may not be the same as the author; in particular, the destructor of Foo
does not know which types were set, but it must locate those objects and call their destructors, noting that the set of types used may be different between instances of Foo
, so this information must be stored in a runtime container within Foo
.
If you're wary about the RTTI overhead implied by std::type_index
and std::any
, we can replace them with lower-level equivalents. For std::type_index
you can use a pointer to a static
tag variable template instantiation (or any similar facility), and for std::any
you can use a type-erased std::unique_ptr<void, void(*)(void*)>
where the deleter is a function pointer:
using ErasedPtr = std::unique_ptr<void, void(*)(void*)>;
std::unordered_map<void*, ErasedPtr> member;
struct tag {};
template<class T> inline static tag type_tag;
member.insert_or_assign(&type_tag<T>, ErasedPtr{new T(value), [](void* p) {
delete static_cast<T*>(p);
}});
Example. Note that once you make the deleter of std::unique_ptr
a function pointer, it is no longer default-constructible, so we can't use operator[]
any more but must use insert_or_assign
and find
. (Again, we've got the same DRY violation / inefficiency, since the deleter could be used as the key into the map; exploiting this is left as an exercise for the reader.)
Template a member variable
You can minimize the amount of code that has to be written for each class -- it doesn't have to be a template specialization and it doesn't have to be an entire class.
class LunchBox
{
public:
std::vector<Apple> m_apples;
};
class ClassRoom
{
public:
std::vector<Student> m_students;
};
// you need one function per type, to provide the member name
auto& get_associated_vector( Student& s ) { return s.m_apples; }
auto& get_associated_vector( ClassRoom& r ) { return r.m_students; }
// and then the decorator is generic
template<typename T>
class accessor_decorator
{
T& peer;
public:
auto& getNthElement( int i ) { return get_associated_vector(peer).at(i); }
auto& takeRandomElement( int i ) { ... }
// many more ways to manipulate the associated vector
auto operator->() { return &peer; }
};
LunchBox lunchBox{};
accessor_decorator<LunchBox> lunchBoxWithAccessor{lunchBox};
auto apple3 = lunchBoxWithAccessor.getNthElement(3);
The simple helper function overload should ideally be in the same namespace as the type, to make argument-dependent lookup work (aka Koenig lookup).
It's also possible to specify the member at the point of construction, if you prefer to do that:
template<typename T, typename TMemberCollection>
struct accessor_decorator
{
// public to make aggregate initialization work
// can be private if constructor is written
T& peer;
TMemberCollection const member;
public:
auto& getNthElement( int i ) { return (peer.*member).at(i); }
auto& takeRandomElement( int i ) { ... }
// many more ways to manipulate the associated vector
auto operator->() { return &peer; }
};
template<typename T, typename TMemberCollection>
auto make_accessor_decorator(T& object, TMemberCollection T::*member)
-> accessor_decorator<T, decltype(member)>
{
return { object, member };
}
LunchBox lunchBox{};
auto lunchBoxWithAccessor = make_accessor_decorator(lunchBox, &LunchBox::m_apples);
auto apple3 = lunchBoxWithAccessor.getNthElement(3);
Derive a templated class' member variable type from a template member type
You can get the type via decltype
, if the names of data member are always the same:
template <class S>
class someClass {
vector< decltype(S::variable) > history; // if S=thingA, make it a double, if S=tingB make it a complex<double>
};
C++: Can I have non-static member variable templates?
Can I have non-static member variable templates?
No.
However, you can use templates to generate a list of members like you describe. Here is an example using recursive inheritance:
template<class T, std::size_t base, std::size_t size>
class Stair;
template<class T, std::size_t base>
class Stair<T, base, base> {};
template<class T, std::size_t base, std::size_t size>
class Stair : Stair<T, base, size - 1> {
protected:
std::array<T, size> arr;
public:
template<std::size_t s>
std::array<T, s>& array() {
return Stair<T, base, s>::arr;
}
};
int main()
{
Stair<int, 2, 10> s;
auto& arr = s.array<9>();
Accessing member variables in a C# template class
You need to make an interface that contains the common properties, then have Thing1
and Thing2
inherit from it. Then, add a constraint on your type parameter <T>
in GroupOfThings
, and you can access the property.
public interface IThing
{
string GroupId { get; set; }
}
public class Thing1 : IThing
{
public string Name {get; set;}
public string Id {get; set;}
public string GroupId {get; set;}
}
public class Thing2 : IThing
{
public string Size {get; set;}
public string Id {get; set;}
public string GroupId {get; set;}
}
public class GroupOfThings<T> where T : IThing
{
public GroupOfThings(List<T> things, string groupID)
{
GroupId = groupID;
Items = things;
// This is the code that I would like to be able to have
foreach(var i in Items)
{
//compiler knows about GroupId from interface
i.GroupId = groupID;
}
}
public List<T> Items;
public string GroupId;
}
Simple way to reference member variables of base class templates
As the solutions, you have to make the name value
dependent to make it visible for name lookup. Besides the one you've showed, you can also:
Use
using
to introduce the name,template<typename T>
struct D1: B1<T> {
using B1<T>::value; // or move it in method's scope according to your intent
D1() {
value = 1; // OK.
}
};Qualify with
this->
.template<typename T>
struct D1: B1<T> {
D1() {
this->value = 1; // OK.
}
};
Access Member Variables using templates
Syntax to acces via member pointer is .*
or ->*
:
class Utilities {
public:
template <typename Container, typename MemberVar, typename Operator>
static void for_all(Container& C, MemberVar memvar, Operator Op)
{
for (auto& element : C) {
((*(element.*memvar)).*Op)();
}
}
};
Demo
Related Topics
Execute C++ from String Variable
Determine If Map Contains a Value for a Key
How to Show Enter Password in the Form of Asterisks(*) on Terminal
How to Use Dynamic Name for Variables in C++
High Delay in Rs232 Communication on a Pxa270
C++ Fatal Error Lnk1120: 1 Unresolved Externals
How to Run Specific Test Cases in Googletest
What Is _Declspec and When Do I Need to Use It
Comparing Character Arrays and String Literals in C++
Why Is Auto_Ptr Being Deprecated
Copying Std::Vector: Prefer Assignment or Std::Copy
Difference Between C++11 Std::Bind and Boost::Bind
How to Create a Type in C++ That Takes Less Than One Byte of Memory