2

I've got this queue class, actually, several that suffer from the same issue - performance will be poor if compiled with a type that has a lengthy copy ctor - the queue is locked during push/pop and the longer it is locked, the greater the chance of contention. It would be useful if the class would not compile if some developer tried to compile it with a 10MB buffer class, (instead of a pointer to it).

It seems that there is no easy way to restrict template parameters to base classes or any other type.

Is there some bodge I can use so that my class will not compile if the parameter is not a pointer to a class instance?

Martin James
  • 24,453
  • 3
  • 36
  • 60
  • 2
    You probably should support move ctors, then. Moving a 10 MB buffer class doesn't have to be expensive at all. – MSalters Apr 13 '12 at 14:21

4 Answers4

6

You can do this in several ways. As another answer points out you can do it with a static_assert (preferably from C++11/Boost although you can roll your own), although I'd recommend checking if it is actually a pointer and not just relying on the size. You can either roll your own or use an existing trait (available in C++11 too) depending on what system you're using:

template <typename T>
struct is_pointer {
  enum { value = 0 };
};

template <typename T>
struct is_pointer<T*> {
  enum { value = 1 };
};

template <typename T>
struct container {
  static_assert(is_pointer<T>::value, "T must be a pointer");
  void push(const T&);
  T pop();
};

struct foo {};

int main() {
  container<foo*> good;
  container<foo> fail;
}

But that raises a bigger point. If your requirement is that you only ever point to things, why not interpret the template parameter like that to begin with? E.g. make your container:

template <typename T>
struct container {
  void push(const T*);
  T *pop();
};

instead of allowing people to specify non-pointer types in the first place?

Finally if you don't want to go down the static_assert road you can just specialise the container for pointer types only and not implement it for non-pointers, e.g.:

template <typename T>
struct container;

template <typename T>
struct container<T*> {
  void push(const T*);
  T *pop();
};

struct foo {};

int main() {
  container<foo*> good;
  container<foo> fail;
}

This still requires explicitly making the type a pointer, still causes compile time failure for non-pointer types, but doesn't need a static_assert or way of determining if a type is a pointer.

Community
  • 1
  • 1
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • This is an old question, but in C++11 they added std::is_pointer http://www.cplusplus.com/reference/type_traits/is_pointer/ – Jameshobbs Jan 08 '16 at 17:57
2

"Is there some bodge I can use so that my class will not compile if the parameter is not a pointer to a class instance?"

Not a bodge, but:

template<class T>
class MyContainer
{
public:
    void AllMemberFunctions( T* in ){}
    void OnlyAcceptTStars( T* in ){}

};

The user defines the type being held, and your functions only accept or handle pointers to that type.

(Or do what STL does, assume some intelligence on the part of the user and forget about the issue.)

Grimm The Opiner
  • 1,778
  • 11
  • 29
0

Use a variant of static assert (just google for many possible implementations). Something like BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(void*)) should do the trick.

zvrba
  • 24,186
  • 3
  • 55
  • 65
  • Just because T is small doesn't mean it has a trivial copy constructor. – Flexo Apr 13 '12 at 14:08
  • Hmh, you're right. But there are also traits helper classes to determine whether the type is, say, a primitive type. So that could be substituted instead of the sizeof test. – zvrba Apr 13 '12 at 14:10
0

Yes, you can do it using static_assert. For example,

template<int N>
class Queue
{
static_assert(N < size, "N < size violated");
...
};
innochenti
  • 1,093
  • 2
  • 8
  • 23