• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

Help with C++ templates

Leros

Lifer
Another question:

Is it possible to have a template argument that is limited to only a few types?

template<typename A, typename B>

Say I wanted to limit A and B to char, short, and int only. Is there a way to do that without writing 9 specializations?

______________________________________________

I have two template types:

template<typename X, typename Y>
class A {

void foo(B<X,don't care> &bObject> {} //how do I do this?

};

template<typename X, typename Z>
class B {

};


I want to write a function in class A that takes any object of type B as long as the first template argument matches. I don't care if the second argument matches. See the foo function in class A.

How do I do this?
 
Last edited:
Try this:

Code:
template<typename A, typename B>
class Foo {};

template<typename A, typename C>
class Bar
{
public:
  template<typename T>
  void baz(Foo<A, T>& f) {}
};

int main()
{
  Foo<int, float> f;
  Bar<int, double> b;
  
  b.baz(f);
  
  return 0;
}

Don't have VS handy to test it but Comeau online accepts it with no complaints.
 
Another question.

Is it possible to have a template argument that is limited to only a few types?

template<typename A, typename B>

Say I wanted to limit A and B to char, short, and int only. Is there a way to do that without writing 9 specializations?
 
Another question.

Is it possible to have a template argument that is limited to only a few types?

template<typename A, typename B>

Say I wanted to limit A and B to char, short, and int only. Is there a way to do that without writing 9 specializations?

If you specifically want only integer primitive types, then just declare your method or object with int explicitly, and you're done. No template needed.
 
If you specifically want only integer primitive types, then just declare your method or object with int explicitly, and you're done. No template needed.

It is very important that the type be preserved. I can't just have it get converted to int.
 
You could inspect the type at run-time:

if (typeid(A) != typeid(short) && typeid(A) != typeid(char) ...)
{
throw exception/assert/ignore etc.
}

Perhaps you want a compile-time error if you try to instantiate, but I'm not sure why would you want that. If the type assumption is used inside class/func and you instantiate with the wrong types, you'll get some kind of compile error anyway. There's always ctrl-c ctrl-v too...
 
You could inspect the type at run-time:

if (typeid(A) != typeid(short) && typeid(A) != typeid(char) ...)
{
throw exception/assert/ignore etc.
}

Perhaps you want a compile-time error if you try to instantiate, but I'm not sure why would you want that. If the type assumption is used inside class/func and you instantiate with the wrong types, you'll get some kind of compile error anyway. There's always ctrl-c ctrl-v too...

I do indeed want that. I don't want to try to explain what I'm doing because it is rather complex. If I can get the following kind of example working, then I can use the same idea to get my program working.

Imagine you have a function foo() that adds three numbers. It accepts chars, shorts, and ints. The return type should be the minimum type required to support the three inputs.

So I would need to generate 27 functions:
char foo(char, char, char);
short foo(char, char, short);
int foo(char, char, int);
short(char, short, char);

etc

Instead, I want to do this with one template function:

template<typename A, typename B, typename C>
MetaProgram<A,B,C>::RETURN_TYPE foo(A a, B b, Cc) {
return a + b +c;
}


I've already have the meta program to deduce the return type. The problem is limiting A, B, and C to only {char, short, int}.
 
Last edited:
So is it like a for a library and you're afraid that someone might try to use it with the wrong types? I still feel you should just define it as a normal template and not care about incorrect types as they would likely generate some kind of error at some point, and only if someone explicitly tries to do something like foo<double, int>...

Anyway, there's a solution to this using C++ traits and static_assert from boost. The following will work:
Code:
template< typename T > struct is_OK { 
  static const bool valid = false;
};

template<> struct is_OK<short> { 
  static const bool valid = true;
};

template<> struct is_OK<char> { 
  static const bool valid = true;
};

template<> struct is_OK<int> { 
  static const bool valid = true;
};

...


template<typename A, typename B> void f(A x, B y)
{
	BOOST_STATIC_ASSERT(is_OK<A>::valid);
	
	// rest of code
}

Basically, is_OK struct has template specializations with valid==true for the types you want, and everybody else is valid==false.

If you don't have boost, you can use something like:
#define mystatic_assert( B ) enum { _myassrt = 1/(int(B)) }

I think this will not generate any code if you don't use _myassrt anywhere. And it will obviously generate a compiler error if B is false. BOOST_STATIC_ASSERT gives a bit better compile error message, but you could just put a comment at the assert line since the compiler will place you there.
 
Back
Top