Does a class template -that takes integer parameter- define multiple classes for different integer inputs?
for ex:
I applied the following code
template<int val>
class MyClass
{
public:
static int var;
};
template<int val> int MyClass<val>::var = val;
int main(int argc, char* argv[])
{
MyClass<5> a;
MyClass<7> b;
MyClass<9> c;
std::cout << a.var << " , " << b.var << " , " << c.var << std::endl;
return 0;
}
Output
5 , 7 , 9
does it mean that a class definition is created for every integer passed as template argument (as the static member variable is different every time) ?
Is there a way to check the generated class definitions? I tried to check map file and assembly code but no luck
Yes, these will be 3 distinct types
You can for instance use C++ Insights to get an idea of the code that the compiler generates from class templates.
#include <iostream>
template<int val>
class MyClass
{
public:
static int var;
};
/* First instantiated from: insights.cpp:14 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class MyClass<5>
{
public:
static int var;
// inline constexpr MyClass() noexcept = default;
};
#endif
/* First instantiated from: insights.cpp:15 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class MyClass<7>
{
public:
static int var;
// inline constexpr MyClass() noexcept = default;
};
#endif
/* First instantiated from: insights.cpp:16 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class MyClass<9>
{
public:
static int var;
// inline constexpr MyClass() noexcept = default;
};
#endiint MyClass<9>::var = 9;
int main(int argc, char ** argv)
{
MyClass<5> a = MyClass<5>();
MyClass<7> b = MyClass<7>();
MyClass<9> c = MyClass<9>();
std::operator<<(std::operator<<(std::cout.operator<<(a.var), " , ").operator<<(b.var), " , ").operator<<(c.var).operator<<(std::endl);
return 0;
}
edit: Altough you see CppInsight is not perfect, as it screwed up the instantiation of the static member variables.
Related
Is there a way to use templates to create a standard constructor of class in your main?
If I have a class:
myclass.h
class myClass
{
private:
float a;
public:
myClass(float _a) {a = _a;}
float getA(){return a;}
~myClass() {}
};
Is there a way to template this in your main like so:
main.cpp
#include "myclass.h"
typedef myClass<5.0> Dummy
int main(int argc, char const *argv[])
{
// EDIT: removed the following typo
// Dummy dummy();
Dummy dummy;
std::cout << dummy.getA() << std::endl;
return 0;
}
Which should output:
> 5.0000000
So that one may define in the main a standard way to construct the instances.
C++17 and Below
Unfortunately C++ does not allow you to use floating point types as non-type template parameters yet. That said, you can fake it by accepting a numerator and denominator as integers and then doing that "math" in the class to get a floating point value. That would look like
template<size_t numerator, size_t denominator = 1> // use a default value so you don't have to specify the denominator for whole values
class myClass
{
private:
float a;
public:
myClass(float _a = static_cast<float>(numerator) / denominator) : a(_a) {}
float getA(){return a;}
~myClass() {}
};
typedef myClass<5> Dummy;
int main(int argc, char const *argv[])
{
Dummy dummy; // notice this isn't Dummy dummy();. That makes a function, not a variable
std::cout << dummy.getA() << std::endl;
return 0;
}
You could also add a default value to numerator if you want to so that you could do
// Pre C++17
myClass<> foo;
//C++17 and later
myClass foo;
C++20
Now that we can use floating point types1 the code can be simplified to:
template<float default_value = 0.0f>
class myClass
{
private:
float a;
public:
myClass(float _a = default_value) : a(_a) {}
float getA(){return a;}
~myClass() {}
};
typedef myClass<5.0f> Dummy;
int main(int argc, char const *argv[])
{
Dummy dummy;
std::cout << dummy.getA() << std::endl;
return 0;
}
1: no compilers actually support this yet, but it is allowed per the standard
Building onto #pptaszni's answer, you could create a "factory factory function":
auto makeMyClassFactory(float value) {
return [=] {
return myClass{value};
};
}
auto const Dummy = makeMyClassFactory(5.0f);
int main(int argc, char const *argv[])
{
auto dummy = Dummy();
std::cout << dummy.getA() << std::endl;
return 0;
}
See it live on Wandbox
You are possibly better off just using a default instance which you make copies of whenever you need a new instance:
#include "myclass.h"
Dummy myClass(5.0);
int main(int argc, char const *argv[])
{
myClass dummy1 = Dummy;
std::cout << dummy1.getA() << std::endl;
myClass dummy2 = Dummy;
std::cout << dummy2.getA() << std::endl;
return 0;
}
Not really, but you can write a factory function (or class if it is more complicated) like this:
myClass createMyClassV5()
{
return myClass(5.0);
}
Unfortunately, you cannot make it a template, because float are not allowed to be template non-type parameters. You could do it with int though.
For the code I am working on, I have a class that uses a "context" singleton. In order to be a bit more coder-friendly, I passes the Singleton class used as a template to the object. For example, something like this:
#include <iostream>
class DefaultCtx {
private:
DefaultCtx() {};
const char *str = "default";
public:
static const char* get()
{
static DefaultCtx instance;
return instance.str;
}
DefaultCtx(DefaultCtx const &) = delete;
void operator=(DefaultCtx const &) = delete;
};
// Context for 64bits.
class Ctx64 {
private:
Ctx64() {};
const char *str = "64";
public:
static const char* get()
{
static Ctx64 instance;
return instance.str;
}
Ctx64(Ctx64 const &) = delete;
void operator=(Ctx64 const &) = delete;
};
template<typename Ctx>
class UsesCtx {
public:
UsesCtx() { std::cout << "Constructed using singleton " << Ctx::get() << std::endl; }
};
This scheme works fine, and I'm quite happy with the need to pass context as template parameter when constructing my objects. However, since Ctx64 is used for 64 bits representation, I wanted to add a little syntaxic sugar and use UsesCtx<64> :
int main() {
UsesCtx<DefaultCtx> a;
UsesCtx<Ctx64> b;
// UsesCtx<64> c; //< I don't know how to achieve that.
}
As I noted here, I don't know how to achieve it. I tried to redefine the class with an integer template, but that gives me the following error (compiled with g++ example.cpp --std=c++14)
// Gives compile error "error: template parameter ‘class Ctx’ redeclared here as ‘int n’"
template<int n>
class UsesCtx {
public:
UsesCtx() { std::cout << "Constructed using singleton " << n << std::endl; }
};
Is there any way I can have my class UsesCtx with both a class template parameter and an int template parameter? Of course, I can always instantiate with UsesCtx<Ctx64>, so this is not vital. But it didn't expected it to be hard to do.
Consider the following.
struct A {
static const int X = 1;
static void printX() {std::cout << "X " << X << std::endl; };
};
struct B: public A {
static const int X = 2;
};
int main(argc argv){
B b;
b.printX();
}
How to force the b.printX() to print value 2?
Both - constant and method - MUST be static. And therefore, virtual methods are not suitable.
For anyone who thinks they know my task better than me and wants to see me rethinking it, I'll explain the goal of my efforts :)
Just imagine class which has behaviour based on set of static constants. The simplest way to implement child class with different set of constants and therefore with different behaviour is derivation of class from previous one with specific set of constant values. It is possible to solve that task using virtual functions. Of cause possible, no question. But this solution will be not very pure in sense of accordance to a theory of modeled entities. Usage of virtual methods in this case will be more a trick than correct implementation.
For example, IR channels have different timing of pulse durations and package structure. It is convenient to define set of child classes (different IR channel implementations) with a specific set of constant values. That values are static because they are common for every object of class and const because they are needed at compile time only. And because internal implementations of base and child classes are slightly different the best relationship between of them are super class - child class.
Is it rationale for my original question now?
You are going to need a template, and to change the inheritance to use the template, as you will see. The trick is to make it work whether the derived class has an X to overshadow the base-class X or not.
template<class C>
struct A {
static const int X = 1;
template<typename T>
static int getX(decltype(T::X)*)
{ return T::X; }
template<typename T>
static void getX(...)
{ return X; }
static void printX()
{ std::cout << "X " << getX<C>(0) << std::endl; }
};
struct B: public A<B> {
static const int X = 2;
};
struct B2: public A<B2> {
// No X
};
int main(){
B b;
b.printX(); // Prints X 2
B2 b2;
b2.printX(); // Prints X 1
}
Just make the value of X a template parameter:
#include <iostream>
template<int XValue=1>
struct A {
static const int X = XValue;
static void printX() {std::cout << "X " << X << std::endl; };
};
template<int XValue=2>
struct B: public A<XValue> {
};
struct C: public B<3> {
};
int main(int, char**){
B<> b;
b.printX();
}
By definition, anything you do with static members will be "overshadowing", not "overriding". You could reimplement "printX()" in "B", but you would not really be overriding the behavior; because this would use overshadowing, the behavior would depend entirely on the compile-time, not runtime, type.
Instead of using static and template, I would just use regular constant attributes and constructors.
For example:
#include <iostream>
struct A {
A(const char* fn, const int X) : filename(fn), X(X) {};
void print() { std::cout << "X = " << X << ", FN = " << filename << std::endl; };
protected:
const char* filename;
const int X;
};
struct B : public A {
B() : A("data.dat", 5) {};
};
int main(int, char **) {
B b;
b.print();
}
Functionally, it does exactly what you want. Output:
X = 5, FN = data.dat
— It's now the compiler's job to optimize those constants. And if you are not intending to use thousands of objects B, it's probably not worth worrying about making those constants static.
Short answer: you can't.
Slightly longer, more complex answer: Well, maybe you can. With templates!
#include <iostream>
template <typename T> struct A
{
static const int X = 1;
static void printX()
{
std::cout << "X=" << T::X << std::endl;
}
};
struct B : public A<B>
{
static const int X = 2;
};
int main(int, char **)
{
B b;
b.printX();
return 0;
}
OK, I'll play along... you want to nest this more than one level deep. Fine.
#include <iostream>
template <int XX> struct T
{
static const int X = XX;
static void printX()
{
std::cout << "X=" << X << std::endl;
}
};
struct AA
{
static const int X = 1;
/* all other members go here */
};
struct A : public AA, public T<AA::X>
{
/* empty - put stuff in AA instead */
};
struct BB : public AA
{
static const int X = 2;
};
struct B : public BB, public T<BB::X>
{
};
struct CC : public BB
{
static const int X = 3;
};
struct C : public CC, public T<CC::X>
{
};
struct DD : public CC
{
static const int X = 4;
};
struct D : public DD, public T<DD::X>
{
};
int main(int, char **)
{
A a;
B b;
C c;
D d;
a.printX();
b.printX();
c.printX();
d.printX();
return 0;
}
You could even skip the static const int X = ...; in every class, and just do public T<1>, public T<2> etc as necessary.
I need to call different versions of a template member function with the same arguments based on certain static members of the template parameters. Here's a sort of simplified version of what I need to do:
class A {
public:
//...
static const char fooString[];
};
const char A::fooString[] = "This is a Foo.";
class B {
public:
//...
static const char barString[];
};
const char B::barString[] = "This is a Bar.";
class C {
public:
//...
static const char fooString[];
};
const char C::fooString[] = "This is also a Foo.";
//Many other classes which have either a fooString or a barString
void doFoo(const char*s) { /*something*/ }
void doBar(const char*s) { /*something else*/ }
template<class T>
class Something {
public:
//This version should be called if T has a static member called "fooString",
//so it should be called if T is either class A or C
void doSomething() { doFoo(T::fooString); }
//This version should be called if T has a static member called "barString",
//so it should be called if T is class B
void doSomething() { doBar(T::barString); }
};
void someFunc()
{
Something<A> a;
Something<B> b;
Something<C> c;
a.doSomething(); //should call doFoo(A::fooString)
b.doSomething(); //should call doBar(B::barString)
c.doSomething(); //should call doFoo(C::fooString)
}
How would I achieve this?
A possible solution:
#include <iostream>
#include <type_traits>
class A {
public:
//...
static const char fooString[];
};
const char A::fooString[] = "This is a Foo.";
class B {
public:
//...
static const char barString[];
};
const char B::barString[] = "This is a Bar.";
class C {
public:
//...
static const char fooString[];
};
const char C::fooString[] = "This is also a Foo.";
void doFoo(const char*s) { std::cout << "doFoo: " << s << "\n"; }
void doBar(const char*s) { std::cout << "doBar: " << s << "\n"; }
template<class T>
class Something {
public:
//This version should be called if T has a static member called "fooString",
//so it should be called if T is either class A or C
template <typename TT = T, typename std::enable_if<TT::fooString != 0, bool>::type = false>
void doSomething() { doFoo(T::fooString); }
//This version should be called if T has a static member called "barString",
//so it should be called if T is class B
template <typename TT = T, typename std::enable_if<TT::barString != 0, bool>::type = false>
void doSomething() { doBar(T::barString); }
};
int main()
{
Something<A> a;
Something<B> b;
Something<C> c;
a.doSomething(); //should call doFoo(A::fooString)
b.doSomething(); //should call doBar(B::barString)
c.doSomething(); //should call doFoo(C::fooString)
}
Output:
doFoo: This is a Foo.
doBar: This is a Bar.
doFoo: This is also a Foo.
I have a base class A with a constant static variable a. I need that instances of class B have a different value for the static variable a. How could this be achieved, preferably with static initialization ?
class A {
public:
static const int a;
};
const int A::a = 1;
class B : public A {
// ???
// How to set *a* to a value specific to instances of class B ?
};
You can't. There is one instance of the static variable that is shared by all derived classes.
Static members are unique in the application. There is a single A::a constant in your system. What you can do is create a B::a static constant in B that will hide the A::a static (if you don't use the fully qualified name:
class A {
public:
static const int a = 10;
};
static const int A::a;
class B : public A {
public:
static const int a = 20;
static void test();
};
static const int B::a;
void B::test() {
std::cout << a << std::endl; // 20: B::a hides A::a
std::cout << A::a << std::endl; // 10: fully qualified
}
You can do this with Curiously recurring template pattern (you'll have to lose the const though).
template <typename T>
class A {
public:
static int a;
};
template <typename T>
int A<T>::a = 0;
class B : public A<B> {
struct helper { // change the value for A<B>::a
helper() { A<B>::a = 42; }
};
static helper h;
};
B::helper B::h;
May be we can try this way as below ::
The benefit of the below is that you don't have to write the code multiple times, but the actual generated code might be big.
#include <iostream>
using namespace std;
template <int t>
class Fighters {
protected :
static const double Fattack;
double Fhealth;
static const double Fdamage;
static int count;
public :
Fighters(double Fh) : Fhealth(Fh) { }
void FighterAttacked(double damage) {
Fhealth -= damage;
}
double getHealth()
{
return Fhealth;
}
static int getCount()
{
//cout << count << endl;
return count;
}
};
const double Fighters<1>::Fdamage = 200.0f;
const double Fighters<1>::Fattack = 0.6f;
int Fighters<1>::count = 0;
class Humans : public Fighters<1> {
public :
Humans(double Fh = 250) : Fighters<1>(Fh) { count++; }
};
const double Fighters<2>::Fdamage = 40.0f;
const double Fighters<2>::Fattack = 0.4f;
int Fighters<2>::count = 0;
class Skeletons : public Fighters<2> {
public :
Skeletons(double Fh = 50) : Fighters<2>(Fh) { count++; }
};
int main()
{
Humans h[100];
Skeletons s[300];
cout << Humans::getCount() << endl;
cout << Skeletons::getCount() << endl;
return 0;
}
This is part of my other code example .. don't mind many other data but concept can be seen.