-1

I have a Base class:

class Base() {
public:
   Base(int, int);
   ~Base();
};

I have multiple classes that inherit from Base:

class childA : public Base {
public:
  childA(int, int, string);
  ~childA();
};

childA::childA(int x, int y, string str) : Base (x, y)
{
// do something here
}

Same for childB, childC, etc

I want to know if it's possible to create childA, childB or childC using a string. I heard about variadic tempaltes but I don't really understand how to use it.

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
RomMer
  • 113
  • 12

2 Answers2

0

Variadic template is a template, which can take an arbitrary number of template arguments of any type. Both the functions could be variadic since dawn of C language (printf function, for example), then macros and now - templates.

You can declare it like this:

template<typename... Arguments> class Variadic;

then specialize it with any number of arguments, including zero:

Variadic<double> instance;
Variadic<double, std::string> instance;
Variadic<> instance;

Then you may use the argument list, known as argument pack, like this:

template<typename... Arguments> void SampleFunction(Arguments... parameters);

Just as in case of variadic functions, the argument pack can be preceded by concrete arguments:

template<typename First, typename... Rest> class BunchOfValues;

There is classic example of variadic template in STL: std::tuple. Some compilers do not support this feature fully or do not support at all, and in their case tuple is implemented through metaprogramming and macro definitions. There is no direct way in C++ to select particular argument from the list, like it is possible with variadic functions. It's possible to use recursion to iterate through them in one direction:

template<typename T> foo(T first)
{
    // do something;
}

template<typename T, typename U, typename ... Args> foo(T first, U second, Args... Rest)
{
    // do something with T
    foo(second, Rest...); 
}

Usually iteration would rely on function overloading, or - if the function can simply pick one argument at a time - using a dumb expansion marker:

template<typename... Args> inline void pass(Args&&...) {}

which can be used as follows:

  template<typename... Args> inline void expand(Args&&... args) {
    pass( some_function(args)... );
  }

  expand(42, "answer", true);

which will expand to something like:

 pass( some_function(arg1), some_function(arg2), some_function(arg3) etc... );

The use of this "pass" function is necessary, since the expansion of the argument pack proceeds by separating the function call arguments by commas, which are not equivalent to the comma operator. some_function(args)...; will never work. Moreover, this above solution will only work when the return type of some_function is not void. Furthermore, the some_function calls will be executed in an unspecified order, because the order of evaluation of function arguments is undefined. To avoid the unspecified order, brace-enclosed initializer lists can be used, which guarantee strict left-to-right order of evaluation. To avoid the need for a not void return type, the comma operator can be used to always yield 1 in each expansion element.

  struct pass {
    template<typename ...T> pass(T...) {}
  };

  pass{(some_function(args), 1)...};

The number of arguments in argument pack can be determined by sizeof...(args) expression.

As of creating initializers that use calls name it is possible only if name is defined at time of writing the code. There stingizer operator # in preprocessor that can be used, e.g.

#define printstring( x ) printf(#x "\n")

printstring( This a dumb idea );

will generate code (assuming that C++ automatically joins string literals):

printf("This a dumb idea \n")

You can declare something like this:

template<typename T> class moniker
{
public:
    moniker(const char* tname);
}

#define declare_moniker(type, name)  moniker<type> name(#type)

How would variadic macro definitions and variadic template interact? I'm not sure. Compiler I have at hand failed, but it isn't C++11. Try that, if interested.

There might be typeid operator supporeted, depending on compiler settings.

const std::type_info& ti1 = typeid(A);

std::type_info got method name(), but string it returns is implementation dependant: http://en.cppreference.com/w/cpp/types/type_info/name

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42
  • ty for this explanation i understand it better than before – RomMer Dec 16 '16 at 17:07
  • now is it possible to quickly explain me how i can create my objects using a string and variadic templates if it's the right way to do it – RomMer Dec 16 '16 at 17:09
  • @Rifzy I'm not sure what you're seeking to implement, why you need name of class (which in case of templates, technically is a long string with ALL arguments given) and in which combination with variadic template use. You may try use typeid(this).name()? – Swift - Friday Pie Dec 16 '16 at 17:14
  • i making a game – RomMer Dec 16 '16 at 17:16
  • @Rifzy and you need to do what? To identify what type your object is in runtime? there are patterns that allow that without storing a string – Swift - Friday Pie Dec 16 '16 at 17:18
  • i'm making a game and i have lot of classes of enemies i want to create different enemies with a function addEntity using a string with the name of the enemy's type and i want to create an object using this string i want to pass "Alien" to my function as parameter and make my function returning a pointer on an Alien object (my class Alien) – RomMer Dec 16 '16 at 17:18
  • @Rifzy that sounds like factory https://en.wikipedia.org/wiki/Factory_method_pattern – Swift - Friday Pie Dec 16 '16 at 17:20
  • i will try that than you – RomMer Dec 16 '16 at 17:21
  • @Rifzy ok, with fixed amount of possible variants that sounds quite simple AND it's good to use macro definitions and, maybe , templates if there are lots of variants - eaiser to maintain code. Things should be interesting (in terms of Chinese curse) if you do procedural generation based on some saved data about object.. maybe you need classes that would create instances of themselves from call of static method. – Swift - Friday Pie Dec 16 '16 at 17:23
  • i checked how it works. Got it. But with this technique how can i pass parameters at the construction of my object – RomMer Dec 17 '16 at 10:48
  • @Rifzy if you have the problem I think of, "how to implement universal way to initialize all created objects", either pass through a parameter pack to variadic constructors (actually, better if you will have some init method that would do initialization), or create data structure that would be able hold data for any kind of object and pass it – Swift - Friday Pie Dec 18 '16 at 09:19
0

In c++14 you could create some helper struct to determine each character of the string you pass at compile-time and to forward it to a type. However string you pass need to be stored in variable with linkage to let compiler to use it as a non-type template parameter:

#include <utility>
#include <type_traits>

template <char... Cs>
struct string_literal { };

template <class T, T &, class>
struct make_string_literal_impl;

template <class T, T &Cs, std::size_t... Is>
struct make_string_literal_impl<T, Cs, std::index_sequence<Is...>> {
    using type = string_literal<Cs[Is]...>;
};

template <class T, T &>
struct make_string_literal;

template <class T, std::size_t N, T (&Cs)[N]>
struct make_string_literal<T[N], Cs>: make_string_literal_impl<T[N], Cs, std::make_index_sequence<N>> {
};

struct Base {
   Base(int, int) { }
   ~Base() { }
};

template <class>
struct Child: Base { 
    using Base::Base;
};

constexpr char const str[] = "abc";

int main() {
    Child<make_string_literal<decltype(str), str>::type> c(1, 1);
}

[live demo]

W.F.
  • 13,888
  • 2
  • 34
  • 81