By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
429,087 Members | 1,508 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 429,087 IT Pros & Developers. It's quick & easy.

Elegant way of making template arguments dependent on user input?

P: n/a
Hey everybody,
I got into serious trouble with template programming. I have a class
which uses three template arguments, say
template<typename Atype, typename Btype, typename Ctype>
class some_class {
};
and I want to make the values of these template arguments dependent on
the input of the program as shown by the following pseudocode:
if (input_for_Atype == "a")
firsttype := first_A;
else if (input_for_Atype == "b")
firsttype := second_A;
//...

if (input_for_Btype == "1")
secondtype := first_B;
else if (input_for_Btype == "2")
secondtype := second_B;
//...

// analogous for Ctype

// instanciate correct version of "some_class"
some_class<firsttype, secondtype, thirdtypeinstance_of_class;

// Begin doing stuff with the class
instance_of_class.do_something();
//...
// End
I hope you get the idea.

The number of choices for each template argument is limited of course,
so a canonical solution would be to write out each possible combination
of the template arguments. This is really ugly, since in my case there
are already 24 possible combinations (2*4*3) for the template arguments,
and there will most likely be more in the future. Also the code would be
redundant, as the part between "Begin doing stuff" and "end" is always
the same for each of the combinations.

My question is whether there is a more elegant way to solve my problem.

I have already tried to do the following. For each of the template
arguments write a function which decides (dependant on the input) the
type of its related template, like this:
template<typename Atype, typename Btype, typename Ctype>
inline void run() {
some_class<Atype, BType, Ctypeinstance_of_class();
// do the stuff... code is only written once!
}

template<typename Atype, typename Btype>
inline void choose_C() {
if (input_for_Ctype == 1)
run<Atype, Btype, first_C>();
else if (input_for_Ctype == 2)
run<Atype, Btype, second_C>();
// ...
}

template<typename Atype>
inline void choose_B() {
if (input_for_Btype == 1)
choose_C<Atype, first_B>();
else if (input_for_Btype == 2)
choose_C<Atype, second_B>();
//...
}

inline void choose_A() {
if (input_for_Atype == 1)
choose_B<first_A>();
else
choose_B<second_A>();
}

int main() {
choose_A();
}
Unfortunately this won't work in my case, since the value of the Atype
template also depends on "input_for_Ctype". In fact, the method choose_A
looks like this:
inline void choose_A() {
if (input_for_Atype == 1 || input_for_Ctype == 1)
choose_B<first_A>();
else
choose_B<second_A>();
}
Now, it is crucial for input_for_Ctype == 1 to use first_A as the Atype,
since it defines some member variables which aren't available in
second_A. Unfortunately my C++ compiler seems to compile the code in the
run method for Atype = second_A and Ctype = first_C as well, though this
path is never taken in the program. This is leading to errors that
second_A won't have the requested members. Declaring all functions
inline as shown above didn't help.
I hope this wasn't too much at once, but the situation seems to be
rather complex. If there are any questions to the problem just feel free
to ask them and I will try to explain it in more detail.
Is there any solution for this or is it just impossible in C++? Of
course an alternative would be to do it with class inheritance and
virtual methods, but this is no option, since performance is most
important (I'm testing algorithms on huge datasets, taking hours of time
already). "Googling" on this problem didn't really reveal anything of use.
Greets and thanks in advance,
Thomas

PS: Maybe this is of use:

# gcc -v
Using built-in specs.
Target: x86_64-suse-linux
Configured with: ../configure --enable-threads=posix --prefix=/usr
--with-local-prefix=/usr/local --infodir=/usr/share/info
--mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64
--enable-languages=c,c++,objc,fortran,java,ada --enable-checking=release
--with-gxx-include-dir=/usr/include/c++/4.1.0 --enable-ssp
--disable-libssp --enable-java-awt=gtk --enable-gtk-cairo
--disable-libjava-multilib --with-slibdir=/lib64 --with-system-zlib
--enable-shared --enable-__cxa_atexit --enable-libstdcxx-allocator=new
--without-system-libunwind --with-cpu=generic --host=x86_64-suse-linux
Thread model: posix
gcc version 4.1.0 (SUSE Linux)
# uname -a
Linux compute6 2.6.16.13-4-smp #1 SMP Wed May 3 04:53:23 UTC 2006 x86_64
x86_64 x86_64 GNU/Linux
Oct 9 '07 #1
Share this Question
Share on Google+
3 Replies


P: n/a
Thomas Pajor wrote:
....
Is there any solution for this or is it just impossible in C++? Of
course an alternative would be to do it with class inheritance and
virtual methods, but this is no option, since performance is most
important (I'm testing algorithms on huge datasets, taking hours of time
already). "Googling" on this problem didn't really reveal anything of use.
You really need to check to see if performance is an issue before you go
spending an effort on it.

If it is user input, you need to instantiate every case possible of your
template. To make it selectable, a base class or a pointer to a
function with the same signature is needed, I prefer an abstract base class.

The most extensible system (no switch or if's) is a generalized factory
system like the one in Austria C++.

Once all classes have been registered with the factory you can simply

Base * p = at::FactoryRegister< Base, Key >( Key( A, B, C ) )();

Any way you look at it, you need to instantiate all the possible types
you care about.
Oct 9 '07 #2

P: n/a
On 2007-10-09 23:12, Thomas Pajor wrote:
Hey everybody,
I got into serious trouble with template programming. I have a class
which uses three template arguments, say
template<typename Atype, typename Btype, typename Ctype>
class some_class {
};
and I want to make the values of these template arguments dependent on
the input of the program as shown by the following pseudocode:
Templates are a compile-time construct. You can not use any information
that is not known at compile-time when instantiating them.

--
Erik Wikström
Oct 9 '07 #3

P: n/a
Erik Wikström wrote:
Templates are a compile-time construct. You can not use any information
that is not known at compile-time when instantiating them.
I'm well aware of this, but I thought the compiler could use the limited
amount of available choices for each template argument to generate all
neccessary versions of the class and instanciate the correct one
depending on the user input.

Basically I was looking for a way to shorten code like this
if (input_choice_A == 1) {
if (input_choice_B == 1) {
some_class<firstA,firstBinstance();
// redundant code
} else {
some_class<firstA,secondBinstance();
// redundant code
}
} else {
if (input_choice_B == 1) {
some_class<secondA,firstBinstance();
// redundant code
} else {
some_class<secondA,secondBinstance();
// redundant code
}
}
Of course, instead of inserting the redundant code each time, you could
write a templated function like this:
template<typename Atype, typename Btype>
void run(some_class<Atype, Btype&instance) {
// Redundant code here only once
}
So it seems to be technically possible to make template values dependent
on user input. But - and this is what really concerns me - I'd need to
define each combination of template arguments manually, which is a LOT
in my case. It would be much shorter (and easier maintainable) if I
could define them in a way as illustrated here
if (input_choice_A == 1)
typedef firstA first_argument; // I know this won't be visible from
outside the if construct
else
typedef secondA first_argument;

if (input_choice_B == 1)
typedef firstB second_argument;
else
typedef secondB second_argument;
And then just instanciate the class with
some_class<first_argument, second_argumentinstance();
The advantage of such a technique becomes more and more obvious the more
combinations for the template arguments there are.
Regards,
Thomas
Oct 10 '07 #4

This discussion thread is closed

Replies have been disabled for this discussion.