-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.

11
  • compile-time string or runtime string? Commented Dec 16, 2016 at 16:23
  • Factory method does exactly that. Commented Dec 16, 2016 at 16:24
  • tell me more about that @seccpur Commented Dec 16, 2016 at 16:28
  • what do you mean using a string? Commented Dec 16, 2016 at 16:30
  • @LorenceHernandez i want a way to create an object using a string with the name of my class Commented Dec 16, 2016 at 16:31

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

11 Comments

ty for this explanation i understand it better than before
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
@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()?
i making a game
@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
|
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]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.