0

I would like to do the following: I have a templated class which takes 3 types:

file: util.h

template <typename T1, typename T2, typename T3>
  DoSomething(string p1, string p2, string p3){
    // Do something. 
  }

main.cc imports a lot of classes and I need to cycle through a lot of class types.

file: main.cc

# include "util.h"
# include "type1.h"
# include "type2.h"
# include "type3.h"
# include "type4.h"
REGISTER("process1", type1::Type1);
REGISTER("process2", type2::Type2);
REGISTER("process3", type3::Type3);
REGISTER("process4", type4::Type4);

int n = NumRegisteredStrings() // returns 4 (for process1...process4)
for (i=0; i < n-2; i++) {
    p1 = FetchStringName(i); 
    p2 = FetchStringName(i+1);
    p3 = FetchStringName(i+2);
    // When i=0, p1, p2, p3 = (process1, process2, process3) and 
    // t1, t2, t3 are (Type1, Type2, Type3)
    // When i=1, p1, p2, p3 = (process2, process3, process4) and
    // t1, t2, t3 are (Type2, Type3, Type4)                      
    const auto t1 = FetchTypeFromRegistry(p1); 
    const auto t2 = FetchTypeFromRegistry(p2); 
    const auto t3 = FetchTypeFromRegistry(p3);

    DoSomething<t1, t2, t3>(p1, p2, p3);
}

It's painful to create too many invocations by hand. I've weakly heard about registries, but don't really know how they work. Is there a good resource with an example to see if I can use that to get this done?

Otherwise, I'll end up writing the following code (which is error prone):

main () {
DoSomething<Type1, Type2, Type3>("process1", "process2", "process3");
DoSomething<Type2, Type3, Type4>("process2", "process3", "process4");
}

What I really want is

void Helper(string string1, string string2, string string3) {
  DoSomething<GetRegisteredType(string1),
              GetRegisteredype(string2),
              GetRegisteredType(string3)>(string1, string2, string3);
}
   main () {
    // I should not have to specify the type names here.
    // They should be automatically inferred in calling the templated function.
    Helper("process1", "process2", "process3");
    Helper("process2", "process3", "process4");
   }
  • 1
    I don't understand the question – The Vivandiere May 23 '15 at 20:11
  • I've explained how it works in my answer, You can use the macros you want. – ahmedsafan86 May 23 '15 at 21:13
  • @Straight Line, I added more clarification by adding a last code snippet. I'm trying to automate that. – underflownoob May 24 '15 at 01:28
  • So basically, you want compile time type mapping using string as key? I believe there is a way to do that using template recursion one char at a time, but its quite expensive at compile time due to a lot of template instantiations (possibly this is no longer the case with `constexpr`). If you search for c++ compile time string hashing using templates you will find something to build off. – Preet Kukreti May 24 '15 at 05:03
  • Answer to a similar (?) question: http://stackoverflow.com/a/41865/1168342 – Fuhrmanator May 25 '15 at 12:28

2 Answers2

0

Your question is very ambiguous, but it looks like you are trying to minimize the amount of similar code you'd have to maintain. That can be done using preprocessor directives.

For example, if you have to do something like this:

a0(arg_0);
b0(arg_0);
a1(arg_1);
b1(arg_1);
a2(arg_2);
b2(arg_2);

You can define a preprocessor directive like this:

#define AB(n) \
  a##n(arg_##n); \
  b##n(arg_##n);

Now the first code snippet is equivalent to

AB(0)
AB(1)
AB(2)

And if you want to iterate over many numbers, you can either use variadic arguments, or Boost.Preprocessor.

For example, using BOOST_PP_REPEAT:

#include <boost/preprocessor/repetition/repeat.hpp>

#define AB(z, n, text) \
  a##n(arg_##n); \
  b##n(arg_##n);

BOOST_PP_REPEAT(3, AB, nil)
SU3
  • 4,323
  • 2
  • 29
  • 55
0

If I understood you right, you want to register types with names or typeid to be able to perform some operation on it later.

This code is tested in visual studio 2013 and is working fine.

#include <iostream>
#include <map>

using namespace std;

class Interface
{
public:
    virtual std::string Greetings() = 0;
};

class Type1:public Interface
{
public:
    Type1()
    {
    }

    ~Type1()
    {
    }

    std::string Greetings()
    {
        return "Hello from Type1";
    }
private:

};

namespace SomeNamespace
{
    class Type2:public Interface
    {
    public:
        Type2()
        {
        }

        ~Type2()
        {
        }

        std::string Greetings()
        {
            return "Hello from SomeNamespace::Type2";
        }
    private:

    };
}

typedef Interface* (*Delegate)(void);//signature of the fucntion pointer

std::map< std::string, Delegate > objectFactories;

template<class Type> Interface* GetInstance()
{
    return new Type();
}

int _tmain(int argc, _TCHAR* argv[])
{
    objectFactories["Type1"] = GetInstance < Type1 > ;
    objectFactories["SomeNamespace::Type2"] = GetInstance < SomeNamespace::Type2 > ;

    for (auto&item : objectFactories)
    {
        cout << "Greetings from '" << item.first.c_str() << "' is \"" << item.second()->Greetings().c_str() << "\"" << endl;
    }

    cin.get();
    return 0;
}

Output

Greetings from 'SomeNamespace::Type2' is "Hello from SomeNamespace::Type2"
Greetings from 'Type1' is "Hello from Type1"
ahmedsafan86
  • 1,677
  • 1
  • 26
  • 46
  • Thanks, can I create a template call like TemplatedFunction DoSomething("Type1", "Type2"); ? – underflownoob May 24 '15 at 01:31
  • The template exists in its generic state as a code only if you use it with specific types the compiler will generate a function for each type, you can look for another design to solve your problem, what is the problem? what do you want to do? – ahmedsafan86 May 24 '15 at 07:21
  • Thanks, I tried to add more detail to what I really want to do in the original question. – underflownoob May 24 '15 at 10:59