Solved

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

Posted on 2002-07-06
21
365 Views
Last Modified: 2013-12-14
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
Comment
Question by:MakeItWork614
  • 9
  • 6
  • 6
21 Comments
 
LVL 30

Accepted Solution

by:
Axter earned 400 total points
ID: 7134669
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 7139451
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
 
LVL 30

Expert Comment

by:Axter
ID: 7139464
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
 
LVL 30

Expert Comment

by:Axter
ID: 7139465
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 7139480
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
 

Author Comment

by:MakeItWork614
ID: 7139664
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 7139779
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
 

Author Comment

by:MakeItWork614
ID: 7140517
>>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
 
LVL 49

Expert Comment

by:DanRollins
ID: 7141498
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
 

Author Comment

by:MakeItWork614
ID: 7142198
>>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
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 49

Expert Comment

by:DanRollins
ID: 7142662
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
 

Author Comment

by:MakeItWork614
ID: 7143400
>>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
 
LVL 30

Expert Comment

by:Axter
ID: 7143751
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 7144321
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
 

Author Comment

by:MakeItWork614
ID: 7151326
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 7151761
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
 

Author Comment

by:MakeItWork614
ID: 7152991
>>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
 
LVL 49

Expert Comment

by:DanRollins
ID: 7153628
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
 
LVL 30

Expert Comment

by:Axter
ID: 7154494
>>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
 
LVL 49

Expert Comment

by:DanRollins
ID: 7155357
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
 
LVL 30

Expert Comment

by:Axter
ID: 7156066
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

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now