-2

I have several small classes that are all peers of each other declared and defined in the same file. A lot of these classes share information. Currently, the type of the shared information is hard-coded for initial development and testing purposes, but I want to templatize (verb form?) the classes. However, if I write the template construct before each class, that creates the possibility that a user could create instances of each class with different type arguments, which will most likely lead to errors in the data or code. Is there a way to force all class instances to be created with the same type?

The only way I can think of doing this is to create an additional init or spawner class with members functions like createInstanceOfA(), createInstanceOfB(), etc., where the user would have to first create an instance of the spawner class with the desired type, then use its member functions to create instances of the other classes. Of course, this would mean that my spawner class would have to stay in sync with whatever utility classes I have (which shouldn't be a problem). However, is there a better way of doing this?

EDIT: As an example, my "ugly solution" (a simple case):

template <typename T>
struct A {
  void manipulate( T arg );
};

template <typename T>
struct B {
  void manipulate( T arg );
};

template <typename T>
struct C {
  void manipulate( T arg );
};

template <typename T>
struct Spawner {
  A<T> createInstanceOfA( void );
  B<T> createInstanceOfB( void );
  C<T> createInstanceOfC( void );
};


int main() {

  // don't allow
  A<int> a;
  B<float> b;
  C<double> c;

  // allow
  Spawner<int> s;
  A<int> s.createInstanceOfA();  // not sure if syntax is correct
  B<int> s.createInstanceOfB();
  C<int> s.createInstanceOfC();

  return 0;
}
LowTechGeek
  • 431
  • 3
  • 12
  • 2
    Why do you want templates, if the code is not generic anyway? This design sounds just plain ugly. – Cat Plus Plus Nov 29 '11 at 19:57
  • If it is an error to templitize the class why template it – rerun Nov 29 '11 at 19:57
  • @CatPlusPlus and rerun: To allow the shared data to be of any type, so long as it is all the same type. I do agree that my "solution" sounds ugly. I'm hoping someone has a better idea. – LowTechGeek Nov 29 '11 at 20:01
  • @LowTechGeek "Any type" and "same type"??? – Pubby Nov 29 '11 at 20:02
  • "Any customer can have a car painted any colour that he wants so long as it is black." — Henry Ford – R. Martinho Fernandes Nov 29 '11 at 20:04
  • @LowTechGeek: Please include a sample code. – Cat Plus Plus Nov 29 '11 at 20:04
  • @pubby I want the shared data to be of any type, but because these utility classes share and manipulate the data (in different ways), each utility class needs to be instantiated with the same template type argument. – LowTechGeek Nov 29 '11 at 20:07
  • 3
    @LowTechGeek: This all sounds to me like a misguided attempt. For any template X and any types T1, T2, X and X are completely different and unrelated types. If they don't provide conversions, then you can't accidentally intermix them, as it will be compilation error. – Cat Plus Plus Nov 29 '11 at 20:13
  • 4
    Possible duplicate of [C++ templates that accept only certain types](https://stackoverflow.com/q/874298/608639), [How to ensure that the template parameter is a subtype of a desired type?](https://stackoverflow.com/q/7020292/608639), etc. – jww Dec 07 '18 at 02:15

3 Answers3

2

What you're asking for doesn't make sense. foo<int> is a different type than foo<float> - you shouldn't be running into issues with the wrong types.

What it seems you want is for to require 3 classes to be instantiated of the same class at the same time. What you want isn't 3 separate classes, but 1 single one: (example is composed of several classes built into one)

template <typename T>
struct col {
  struct t1 {
    T data;
  } a;
  struct t2 {
    T data;
  } b;
};

col<int> foo;
foo.a.data = 5;
foo.b.data = 7;

void process_stuff(col<int>::t1 a) {
  // ...
}
process_stuff(foo.a);
Pubby
  • 51,882
  • 13
  • 139
  • 180
  • Your solution is the same as mine (basically), which brings up two questions: 1) I take it there is no _better_ way to do this (which was my original question), and 2) because you, me, and @manler (after edit) pretty much arrived at the same conclusion, I don't understand why no one could seem to understand my question. Could you please explain to me what was so unclear about my original post so that I don't make the same mistake in the future? Thx. – LowTechGeek Dec 01 '11 at 20:07
1

What you're trying to achieve is called concepts by it's technical name, and there is a Boost library, ConceptCheck, that you can use to implement this.

You could also use std::enable_if and SFINAE (Substition Failure Is Not An Error).

But templates are meant to make code generic, and it doesn't really sound like that is what you want. I would reconsider your design.

Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
1

You can specialize the templates. So if you do:

template<typename T> class A;

template<>
class A<int>
{...};

template<>
class A<double>
{...};

Then if you or someone else tries to create a

A<std::string> a;

there will be a compile error because that type is not specialized.

But perhaps this is not what you want?

Edit:

I somewhat misunderstood the question. Perhaps you can solve this issue by controlling the creation of the classes? Like through a factory? If you only allow creation of the classes through the factory then you should be able to enforce the same type on multiple templates. Perhaps this is just pushing the problem to the factory class...

Good luck!

mantler
  • 859
  • 1
  • 7
  • 22