[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 375
  • Last Modified:

How to stop a non-POD class from compiling in template

I want to be able to prohibit a non-POD class from being able to be compiled in a template class.
Is there any way to do this during compile time?

template<class T>
class foo
{
public:
T TargetObject;  //Don't want non-POD objects here
};

0
MakeItWork614
Asked:
MakeItWork614
  • 9
  • 6
  • 6
1 Solution
 
AxterCommented:
You could try adding the following to your distructor:

~foo()
{
     static const struct
     {
          union only_pod_objects_are_compatible_with_this_template_class
          {
               char c;
               T t; // invalid if T is non-POD
          };
     }pod_only_instance;
}
0
 
DanRollinsCommented:
MakeItWork614,
What is your goal here?  What problem are you ultimately trying to solve?

Axter,
Why does that work?  What does the error message look like?  Perhaps a
 
   #pragma message( "please dont DO THAT!")

would be in order.
 
-- Dan
0
 
AxterCommented:
Full example:

#include <string>

template<class T>
class foo
{
public:
     T TargetObject;  //Don't want non-POD objects here
     ~foo()
     {
          static const struct
          {
               union only_pod_objects_are_compatible_with_this_template_class
               {
                    char c;
                    T t; // invalid if T is non-POD
               };
          }pod_only_instance;
     }
};

class Wiget1
{
public:
     char data[32];
};

class Wiget2
{
public:
     std::string data;
};

int main(int argc, char* argv[])
{
     foo<Wiget1> ThisWillCompile;
     foo<Wiget2> ThisWillNotCompile;
     return 0;
}
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
AxterCommented:
The above example code will produce the following error:
error C2621: union 'only_pod_objects_are_compatible_with_this_template_class' : member 't' has copy constructor
0
 
DanRollinsCommented:
O I C -- the cleverly-named union makes the error message explain what is going on.  Good one!  

Can you think of why MakeItWork614 might want this 'feature'?   I mean, I can think of lots of ways to make a compiler generate error messages.  Wouldn't it be more sensible to design the object so that it *can* be included in a template?

-- Dan
0
 
MakeItWork614Author Commented:
DanRollins,
I have a template class that writes the content of an object to a file.
Since it's not pratical to write a non-POD object to a file, I'm trying to make it so that the template class can't compile with a non-POD object.

Axter,
Your method works pretty good, except it still compiles if a pointer is used.
class Wiget_ptr
{
public:
    char *data;
};

foo<Wiget_ptr> ThisWillCompile;

Is there any way to stop objects containing pointers from being able to compile.
0
 
DanRollinsCommented:
What about a pure virtual function named write_to_file() ?  If the user does not provide an override, the compiler will show an error.  Or are tmplate classes limited in such a way to make that impossible?

-- Dan
0
 
MakeItWork614Author Commented:
>>What about a pure virtual function named write_to_file
>>() ?  

The template needs to be able to work with any POD object, which includes the build in types (int, long, char[]).
If I add this requirement, the template class will no longer be able to work with build in types.

I dont' want to take functionallity away from the template class in order to enforce POD only objects.
0
 
DanRollinsCommented:
Wouldn't it be possible to include built-in handlers for such built-in datatypes?  While you are at it, you could supply handlers for common types such as std::string, etc.  And the Xtremely Kool thing would be that you could then support non-POD data types by user-defined overrides and this whole question becomes moot!
<bows>
-- Dan
0
 
MakeItWork614Author Commented:
>>Wouldn't it be possible to include built-in handlers for
>>such built-in datatypes?

The code already works for build-in data types.  Why would I create a built-in handler for them?

>>While you are at it, you could supply handlers for
>>common types such as std::string

I could do that, but that still would not solve my main problem.  Which is that the code will not work with custom non-POD objects.
That's my primary question.  How can I make it so that non-POD objects can not be compiled with my template class.

Axter's solution will work with most non-POD objects, but objects that have pointers are still able to compile.
0
 
DanRollinsCommented:
You can save a pointer to disk.  It's just a number.  What happens if you use that template with an int* or char* ?

-- Dan
0
 
MakeItWork614Author Commented:
>>You can save a pointer to disk.
Yes, you can save them, but when you read them again, they're not valid.
They're not garanteed to be valid in the same session, and they're diffinitely not going to be valid if you close the program, and restart it again.
Here's an example template class

template<typename T>
class ObjectStorageHandlr
{
public:
     ObjectStorageHandlr(T &Obj_) : Obj(Obj_){}
     void Save(ostream &os)
     {
          os.write((char*)&Obj, sizeof(Obj));
     }
     void Get(istream &is)
     {
          is.read((char*)&Obj, sizeof(Obj));
     }
     T &Obj;
};

class foo
{
public:
     int i;
     long l;
     float f;
     char data[32];
     int x;
};

class wiget
{
public:
     int i;
     long l;
     float f;
     char *data;
     int x;
};

void Test1a()
{
     char *buffer = new char[32];
     strcpy(buffer,"test");
     wiget w = {1,2,3,buffer};
     ObjectStorageHandlr<wiget> foo_ObjectStorageHandlr(w);
     ofstream mystream("test1.obj");
     foo_ObjectStorageHandlr.Save(mystream);
     mystream.close();
     delete buffer;
}

void Test2a()
{
     foo f = {1,2,3,"test", 99};
     ObjectStorageHandlr<foo> foo_ObjectStorageHandlr(f);
     ofstream mystream("test2.obj");
     foo_ObjectStorageHandlr.Save(mystream);
     mystream.close();
}

void Test1b(wiget &w)
{
     ObjectStorageHandlr<wiget> foo_ObjectStorageHandlr(w);
     ifstream mystream("test1.obj");
     foo_ObjectStorageHandlr.Get(mystream);
     mystream.close();
}

void Test2b(foo &f)
{
     ObjectStorageHandlr<foo> foo_ObjectStorageHandlr(f);
     ifstream mystream("test2.obj");
     foo_ObjectStorageHandlr.Get(mystream);
     mystream.close();
}

int main(int argc, char* argv[])
{
     Test1a();
     Test2a();
     wiget w;
     foo f;
     Test1b(w);
     Test2b(f);
     cout << f.data << endl;//Good.  Will display "test"
     cout << w.data << endl;//Bad!!! Will display junk
     return 0;
}

wiget object will display junk because the string it was pointing to, no longer exist.
This will happen with any non-POD object.  So the code will only work with POD objects.
0
 
AxterCommented:
If you look in the boost library, there's some code for POD checking.
Look for the following:

//In utility\compressed_pair_test.cpp
template <> struct is_empty<empty_UDT>
{ static const bool value = true; };
template <> struct is_empty<empty_POD_UDT>
{ static const bool value = true; };
template <> struct is_POD<empty_POD_UDT>
{ static const bool value = true; };
#else
template <> struct is_empty<empty_UDT>
{ enum{ value = true }; };
template <> struct is_empty<empty_POD_UDT>
{ enum{ value = true }; };
template <> struct is_POD<empty_POD_UDT>
{ enum{ value = true }; };

// In test\boost_has_sgi_type_traits.cxx
typedef ::__type_traits<foo_type>::is_POD_type isp;

//In tests\is_function_test.cpp
value_test(false, ::boost::is_POD<T>::value);

You can download the boost library from the following link:
http://www.boost.org/
0
 
DanRollinsCommented:
Of course.  widget fails becasue it contains a pointer.  You could design the template class to dereference the pointer and save (and restore) the data to which it points.  

It just makes more sense to provide a virtual pure function for the user to override.  

-- Dan
0
 
MakeItWork614Author Commented:
DanRollins,
>>It just makes more sense to provide a virtual pure
>>function for the user to override.  

This makes sence for complex objects (NON-POD), but I'm trying to create code specifically for simple POD objects.

If most of the objects I'm using with my template are POD objects, it would be a waste of time to add this extra function to every POD object I want to use with my template class.

I want to use the generic function with my POD objects, there-by not needing to add extra interface to the POD objects.
And I'm going to handle my non-POD objects with a different function, that would require the non-POD object to have the extra inteface.

But I want to make sure that no one mistakenly tries to use the POD-Only function with a non-POD object.

Thank you for your suggestions, but could you please try to answer my original question?


Axter,
I looked at boost, and it looks like I'm going to have to use the entire boost facility just to use the POD dectection functionallity.

If no one else comes up with a better answer by Monday, I'll award you the points.
0
 
DanRollinsCommented:
Maybe you could try to coerce the the object into say, a char pointer.  If the compiler allows it, then it is a pointer data type and you can make it cause an error.  Axter might be able to think of some way to go about doing that...  All I do is think of goofy ideas.  Axter is the STL mechanic around here.

-- Dan
0
 
MakeItWork614Author Commented:
>>Maybe you could try to coerce the the object into say, a >>char pointer.  If the compiler allows it, then it is a
>>pointer data type and you can make it cause an error.

That only works if the object itself is a pointer.  If one of the objects members is a pointer, then it can't be detected using that method.

Axter,
Do you have any other ideas?
0
 
DanRollinsCommented:
I can't think of any way to access the individual members of a class, without knowing thier names.  So even using a test such as dynamic_cast<T> can't get to the member level to do testing (even if you could use it to somehow fail gracefully).

One suggestion I saw on google groups was to add another template parameter, isPod, with the default set to false.  That way you at least force the programmer to lie about it.  

But aren't pointer *allowed* in POD classes?  A pointer requires no constructor or destructor.  So the question is:  How to prevent compilation of any object that is non-POD and also contains no members which are pointers, right?

-- Dan
0
 
AxterCommented:
>>But aren't pointer *allowed* in POD classes?
Yes they are.  That's why the method I posted on my first comment does not prevent pointers from being members of the object.
0
 
DanRollinsCommented:
Axter,
have you ever heard of any technique that would allow a template or a macro to examine/enumerate the individual members of a class?  I've been searching but nothing comes to mind.
-- Dan
0
 
AxterCommented:
DanRollins,
>>have you ever heard of any technique that would allow a
>>template or a macro to examine/enumerate the individual
>>members of a class?  I've been searching but nothing
>>comes to mind.
I don't beleive there's any such method.

MakeItWork614,
>>Do you have any other ideas?
In looking at the boost code, I think at best it's only going to be able to do what my code in my original post does.

STL uses the overloaded insertion (<<) and extraction (>>) operators as a generic method to move different data type values to and from a persistent storage medium.

MFC uses CArchive, which uses overloaded insertion (<<) and extraction (>>) operators to perform writing and reading operations.

It would seem that both the STL developers and the MFC developers decided these overloaded operators to be the best method for generic data type storage interface.

I think if there was a safer method to move generic data types, that one of these two group of developers would have came up with it.

With that said, IMHO, I think you only have two choices.

1. Use the overloaded insertion (<<) and extraction (>>) operators as used in both the STL and MFC.  This will make it easier for other developers to learn and understand the interface to your template class.  This would also make your code safer.

2. Use the method I posted that will at least prevent non-POD objects from been compiled, and add some comments to your template class that would instruct other developers of the pointer restriction.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 9
  • 6
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now