Click here to Skip to main content
15,885,435 members
Please Sign up or sign in to vote.
3.00/5 (3 votes)
See more:
I'm having trouble wrapping my head around this and Mr. Google doesn't seem to know much about it either or I'm just not querying correctly, probably he latter but I've got a template;

C++
template<class T> class CSmartArray
{
   public:
     CSmartArray(...);

      blah...blah...blah

   private:
      T& m_preset_value;  //<=== The value to set
};

template <class T> T& CSmartArray<T>CSmartArray(...)
{
   //How do I set the following value to some default value such as zero?
   m_preset_value = 0;     //Nope
   m_preset_value = (T)0;  //Nope
   m_preset_value = (T&)0; //Nope
}


Question is how do I set the m_preset_value to some default value such as zero?

It's probably very simple but am not seeing it but how do I set any value to m_preset_value?

Urgent send code plz...... :)

Thanks Y'all

BTW Templates using GCC is a PITA!
Posted
Updated 13-Aug-13 8:08am
v3
Comments
Sergey Alexandrovich Kryukov 13-Aug-13 13:58pm    
What code? What are you asking about? What are you trying to achieve?
—SA
H.Brydon 13-Aug-13 17:37pm    
Good question (with perhaps confusing details per the comments and solution text).

+5 to offset whomever downvoted you.
Mike Hankey 13-Aug-13 17:55pm    
Thanks, looks like I set off a fire storm?

As an aside, down voting only matters if you care. :)
Philippe Mori 13-Aug-13 19:12pm    
By the way, even though I have already provided a solution, I just noticed that the class is named CSmartArray.

First, why do you need such a class when there is already a std::vector class?

Second, even you still want to use that class and are satisfied with using default value of T, then why not used std::vector for the implementation as it already handle expanding the array with default value of T.
Mike Hankey 13-Aug-13 19:33pm    
Zero, I thought this would be a generic question as GCC now supports C++11 anyway;

First, I am developing this for an embedded system using GCC.

Second, refer to first!

If this were to be developed using VS I would not be having this problem but GCC error messages are so vague that sometimes they have nothing to do with the problem at hand so it's been a PITA to say the least but I'm starting to catch on and eye the nuances.

Thanks for your feedback!

This worked for me (in VS):

C++
template<class T> class CSmartArray
{
   public:
     CSmartArray();

   private:
      const T& m_preset_value;
};

template <class T> CSmartArray<T>::CSmartArray() : m_preset_value(0)
{
   
}


Not sure if it's quite what you want though. (Note I had to make it a const reference. You might just want to use a pointer here instead, it will probably be easier.)
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 13-Aug-13 14:59pm    
This is not really a solution, because you simply create a reference but provide no a way to really initialize the value of unknown type.
This is not so trivial thing with templates. Please see my answer where I discuss it.
—SA
If we take a look at the generated code then a reference is exactly the same as a pointer. On language level syntactically references have more strict rules: a reference has to be initialized exactly once where you declare/define it. If the reference is the member variable of a class then you have to initialize it from the initializer list of every constructor of the class. A reference can not be changed later to point to something else. After declaration and initialization the identifier of the reference variable works as if it was the identifier of the object to which the reference points. For this reason initializing a reference to zero has no point. If you want to change the reference after initialization to point to something else then you want to use a pointer instead of a reference.
 
Share this answer
 
Comments
Mike Hankey 13-Aug-13 14:39pm    
Excellent I had forgotten about the initialize once rule and you hit it right on the head. I've not worked much with templates and it's been a learning experience.
Thanks!
pasztorpisti 13-Aug-13 14:49pm    
You are welcome!
Sergey Alexandrovich Kryukov 13-Aug-13 15:02pm    
This is all correct but actually does not solve the problem of initialization of the value itself, the value of the unknown type.
Ideally, this problem could be solved with, say, template parameter constraints.
I discuss this problem in my answer and provide a really simple work-around, please see.
—SA
It does not make much sense to have a reference member to an "unknown" type. If this is really what you want to do (assuming that a default constructor exists), you would also have to implement the destructor and ensure that the object is not copyable...

If not, then you have to ensure that the type is a POD type (rules are a bit different with C++ 11 but since I don't know all details).

Thus, you would have something like this (for simplicity all functions are defined inline):
C++
template<class T> class CSmartArray
{
public:
  CSmartArray() : m_preset_value(*new T())
  {
  }

  ~CSmartArray()
  {
    delete &m_preset_value;
  }

private:
  CSmartArray(const CSmartArray &); // No copy
  CSmartArray& operator=(const CSmartArray &); // No copy

  T& m_preset_value;
};


If an instance is used, then it simplify to this (this is what I would recommand to do):
C++
template<class T> class CSmartArray
{
public:
  CSmartArray() : m_preset_value() // Empty () will force default value in that case since a long time.
  {
  }

private:
  T m_preset_value;
};


By the way, this is not very flexible as it is not possible to create object not using the default constructor.
 
Share this answer
 
v2
What you are trying to achieve does not make sense, because the template parameter is any arbitrary type, and an arbitrary file does not have a concept of "null", but it does not even have to support a concept of some "default initial value". Nothing can be assumed for this type.

There are some work-around approaches. Let's think.

It may seem that you can internally use the pointer to T as your private member m_preset_value. Then you could assign this member to the 0 pointer, regardless of the actual type of T. However, it would not solve problem, only delay it, as you don't know the constructor for T if it is required, so how one would instantiate it?

The simplest real resolution could be something like this:
C++
template <class T> class SmartArray {
protected:
	T m_preset_value;
	virtual void Initialize() = 0;
public:
	void SomeMethod() { m_preset_value = Initialize(); } // could be anything, for example, constructor
};


This way, with each instantiation of the template you should also create a derived class and the virtual method should be overridden:
C++
class BooleanSmartArray : public SmartArray<bool> {
protected:
    virtual void Initialize() { m_preset_value = 0; }
};


This may seem to be not very convenient. As an alternative, you would need to use something like generic constraints of CLI (.NET, in particular). This way, you could create some interface class with operations like Initialize and more. Then, instead of arbitrary unconstrained type T, you could indicate that the template parameter is contrained to be derived from this interface class.

You can see these suggestions by Bjarne Stroustrup:
http://www.stroustrup.com/bs_faq2.html#constraints[^].

Another approach is implemented in boost: http://www.boost.org/doc/libs/1_36_0/libs/concept_check/concept_check.htm[^].

See also:
http://en.wikipedia.org/wiki/Boost_%28C%2B%2B_libraries%29[^],
http://www.boost.org/[^].

And if you can use C++11, you can think about the use of template std::initializer_list:
http://en.wikipedia.org/wiki/C%2B%2B11#Initializer_lists[^]

—SA
 
Share this answer
 
v2
Comments
pasztorpisti 13-Aug-13 15:34pm    
This time I must disagree, I think you try to solve a completely different problem. When you store a pointer or reference in a template to an unknown type you usually initialize that reference or pointer with another reference/pointer your receive as a constructor/method parameter so you don't have to know the type. On the other hand in C++ you can expect the type to have a default (or any other kind of parametrized) constructor so you can create instances of that type locally (in contrast for example to java where they solved templates with a very stupid type erasure for some reason). On the other hand you have another serious mistake in your solution: calling a virtual method from a constructor is basically a bug in C++. However you can aid it with a trick by introducing an additional template parameter that must be the derived type, this trick also eliminates the cost of virtual method call:

template <class T, class Derived> class SmartArray {
protected:
T m_preset_value;
public:
void SomeMethod() { m_preset_value = static_cast<Derived*>(this)->Initialize(); } // could be anything, for example, constructor
};

class MyClass : public SmartArray<int, MyClass>
{
void Initialize() {
...

Initialize() can be normal static function. Some info for those interested: This is called "static polymorphism" in C++.
Sergey Alexandrovich Kryukov 13-Aug-13 15:43pm    
If it's static, how can you provide specialized code per concrete type? Ultimately, you would need to assign 0 for one type and something else for another.

Even if OP does not want such initialization, this is a real problem. It actually depends on what the class does. The method like this initialization maybe not required. For example, if the template class is a container, it only make sense to transparently pass data from the user.

—SA
pasztorpisti 13-Aug-13 15:54pm    
I solved such problems with type traits. One such template I often use is my TAutoHandle template. It works like an auto_ptr/unique_ptr but it stores different kind of handles (like FindFirstFile handle, socket handle, ...). In case of handles you must be able to tell which value is invalid (zero or -1?) you have to tell how to close it (FindClose() or closesocket(), ...).

template <typename T, typename Traits=ItemTraits<T> > class SmartArray {
public:
SmartArray()
{
Traits::Initialize(m_preset_value);
}
private:
T m_preset_value;
};

// default type traits implementation
template <typename T> class ItemTraits {
public:
static void Initialize(T& val) {
val = 0;
}
// TODO: add any other type specific operation or constant
};

struct SComplexType
{
int xxx;
};

template<> class ItemTraits<SComplexType>
{
public:
static void Initialize(SComplexType& t) {
// TODO
}
};

class SocketItemTraits {
public:
static void Initialize(SOCKET& sock) {
sock = INVALID_SOCKET;
}
};



int run()
{
SmartArray<SComplexType> ct;
SmartArray<bool> bt;
// I didn't use template specialization for type traits here because many handle types are
// typedeffed to void* so all of them would match the same ItemTraits sepcialization.
SmartArray<SOCKET, SocketItemTraits> st;
Sergey Alexandrovich Kryukov 13-Aug-13 16:30pm    
That's the different stuff, would make a really excellent answer.
—SA
pasztorpisti 13-Aug-13 17:24pm    
Thank you! But if OP is okay with the simple answer about reference initialization...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900