Static variable inside a template base class - c++

This prints nothing:
#include <iostream>
template <typename Derived>
struct A
{
static int test()
{
std::cout << "test" << std::endl;
return 0;
}
static inline int a = test();
};
struct B : public A<B>
{
};
int main(int argc, char** argv)
{
return EXIT_SUCCESS;
}
But this does:
#include <iostream>
template <typename Derived>
struct A
{
};
struct B : public A<B>
{
static int test()
{
std::cout << "test" << std::endl;
return 0;
}
static inline int a = test();
};
int main(int argc, char** argv)
{
return EXIT_SUCCESS;
}
And also this:
#include <iostream>
struct A
{
static int test()
{
std::cout << "test" << std::endl;
return 0;
}
static inline int a = test();
};
struct B : public A
{
};
int main(int argc, char** argv)
{
return EXIT_SUCCESS;
}
Not sure why or a workaround. I need the 'Derived' type to register it into a static table.

The reason why the first snippet doesn't print anything is that the static variable is not instantiated. You have to use that variable in order to instantiate it.
[temp.inst]/2
The implicit instantiation of a class template specialization causes
the implicit instantiation of the declarations, but not of the
definitions, default arguments, or noexcept-specifiers of the class
member functions, member classes, scoped member enumerations, static
data members, member templates, and friends
As a workaround, you can just use that variable:
int main(int argc, char** argv)
{
(void) B::a;
return EXIT_SUCCESS;
}

Since A is a template class, the static inline function/variable are not actually instantiated from the template unless they are used. Thus, you could do e.g. this:
#include <iostream>
template <typename Derived>
struct A
{
static int test()
{
std::cout << "test" << std::endl;
return 0;
}
static inline int a = test();
};
struct B : public A<B>
{
static inline int b = a;
};
int main(int argc, char** argv)
{
return 0;
}
Demo

The (automatic) solution, as pointed here is to create a constructor that uses the registration variable. Also, the variable will be initialized only if an object is constructed.
#include <iostream>
template <typename Derived>
struct A
{
A()
{
a = 0;
}
static int test()
{
std::cout << "test" << std::endl;
return 0;
}
static inline int a = test();
};
struct B : public A<B>
{
};
int main(int argc, char** argv)
{
B b;
return EXIT_SUCCESS;
}
The 'a = 0' is to avoid a warning of unused variable. Overhead should be minimal.
Demo

Related

invalid use of incomplete type with default template

I would like to create a C++ class with a default template parameter. However, I am having the following error:
error: invalid use of incomplete type
The code is the follow:
#include <iostream>
#include <string>
#include <array>
typedef std::array<double, 3> vec;
enum Op {Op1, Op2, Op3};
template<class T, enum Op S=Op1>
class classA
{
public:
class classInsideA
{
public:
classInsideA() {}
void tst()
{
std::cout << "inside A"<< std::endl;
}
};
void foo();
};
template<class T>
void classA<T>::foo() // not working
{
std::cout<< "I am being called in here" << std::endl;
}
int main(int argc, char** argv)
{
classA<vec> obj2;
return 0;
}
I would like that the default template would not change any of the current syntax in the class classA.
How can I fix this?
Edit:
Making the function have 2 template parameters, works.
template<class T, Op S>
void classA<T, S>::foo()
{
std::cout<< "I am being called in here" << std::endl;
}
But if the function has a default parameter, why do I need to specify the two templates. Shouldn't assume the default one?
Simply a typo I believe! You class has two template parameters and your function definition must also use both. See the full example below or here
typedef std::array<double, 3> vec;
enum Op {Op1=99, Op2, Op3};
template<class T, Op S=Op1>
class classA
{
public:
class classInsideA
{
public:
classInsideA() {}
void tst()
{
std::cout << "inside A we use Op value"<< S << std::endl;
}
};
classInsideA dummy;
void foo();
};
template<class T, Op S>
void classA<T, S>::foo() // not working
{
std::cout<< "I am being called in here and we use Op value" << S << std::endl;
}
int main(int argc, char** argv)
{
classA<vec> obj2;
obj2.dummy.tst();
obj2.foo();
return 0;
}

How to use function pointer between 2 classes

i have 2 classes say "Class A" and "Class B". i tried to declare the function pointer prototype in "Class A" and use it in "Class B", but failed. Please look in to my sample code and assist me how to make it success.
#include "stdafx.h"
#include <iostream>
using namespace std;
class A
{
public:
int (*funcPtr)(int,int);
void PointerTesting(int (*funcPtr)(int,int))
{
//i need to get B::test as an function pointer argument
}
};
class B
{
public:
int test(int a,int b)
{
return a+b;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
int (A::*fptr) (char*) = &B::test;
getchar();
return 0;
}
Recommendation: Use < functional >, std::function and std::bind
#include <iostream>
#include <functional>
using namespace std;
class A {
public:
using FnPtr = std::function<int(int, int)>;
void PointerTesting(const FnPtr& fn) {
//i need to get B::test as an function pointer argument
// Example: Print 1 and 2's sum.
int result = fn(1, 2);
std::cout << "Result: " << result << std::endl;
}
};
class B {
public:
int test(int a,int b) {
return (a+b);
}
};
int main(int argc, char* argv[]) {
A a;
B b;
A::FnPtr ptr = std::bind(&B::test, b, std::placeholders::_1, std::placeholders::_2);
a.PointerTesting(ptr);
getchar();
return 0;
}
http://en.cppreference.com/w/cpp/utility/functional/bind
http://en.cppreference.com/w/cpp/utility/functional/function

MSVC error - error C2373: 'description': redefinition; different type modifiers

#include <iostream>
#include <type_traits>
namespace MyNS {
struct Test1 {};
template <typename > class Test;
template <> class Test<Test1> {
public:
constexpr static char const *description[] = { "X1", "Y1",};
};
constexpr char const *Test<Test1>::description[];
static const char * getDesc(int i) {
return MyNS::Test<MyNS::Test1>::description[i];
}
}
int main()
{
std::cout << MyNS::getDesc(0) << std::endl;
}
This fails with MSVC (error C2373: 'description': redefinition; different type modifiers), but compiles successfully on GCC 4.8.
Is there a workaround to successfully build with MSVC and GCC both?
It seems that MSVC wants us to precise the array length, this should work :
#include <iostream>
#include <type_traits>
namespace MyNS {
struct Test1 {};
template <typename > class Test;
template <> class Test<Test1> {
public:
constexpr static char const *description[2] = { "X1", "Y1",};
};
constexpr char const *Test<Test1>::description[];
static const char * getDesc(int i) {
return MyNS::Test<MyNS::Test1>::description[i];
}
}
int main()
{
std::cout << MyNS::getDesc(0) << std::endl;
}
EDIT : You just have to precise the length in the first definition.
Remove the redefinition of description and it compiles. You also need tor return a value from main.
#include <iostream>
#include <type_traits>
namespace MyNS {
struct Test1 {};
template <typename > class Test;
template <> class Test<Test1> {
public:
constexpr static char const *description[] = { "X1", "Y1",};
};
//constexpr char const *Test<Test1>::description[];
static const char * getDesc(int i) {
return Test<Test1>::description[i];
}
}
int main()
{
std::cout << MyNS::getDesc(0) << std::endl;
return 0;
}

Why are overloaded inherited static functions ambiguous?

this is what I tried (the functions "fun" must be static):
#include<iostream>
class A
{
public:
static void fun(double x) { std::cout << "double" << std::endl; }
};
class B
{
public:
static void fun(int y) { std::cout << "int" << std::endl; }
};
class C
:
public A,
public B
{
};
int main(int argc, const char *argv[])
{
double x = 1;
int y = 1;
C::fun(x);
C::fun(y);
return 0;
}
and using g++ (GCC) 4.8.1 20130725 (prerelease), I got the following error:
main.cpp: In function 'int main(int, const char**)':
main.cpp:27:5: error: reference to 'fun' is ambiguous
C::fun(x);
^
main.cpp:12:21: note: candidates are: static void B::fun(int)
static void fun(int y) { std::cout << "int" << std::endl; }
^
main.cpp:6:21: note: static void A::fun(double)
static void fun(double x) { std::cout << "double" << std::endl;
So my question is: how come in C++ if I can override member functions, and not static functions? Why isn't overloading is not working in this scenario? I would expect the compiler to bring "fun" into the namespace C:: and then do name mangling and use overloading to distinguish C::fun(int) and C::fun(double).
You need to put them into scope yourself:
class C
:
public A,
public B
{
public:
using A::fun;
using B::fun;
};
What you need is in class C's definition:
public:
using A::fun;
using B::fun;
It is not clear what fun() method you want to call, therefore you must specify which one you want:
int main(int argc, const char *argv[])
{
double x = 1;
int y = 1;
A::fun(x);
B::fun(y);
return 0;
}

How to define a function pointer pointing to a static member function?

#include "stdafx.h"
class Person;
typedef void (Person::*PPMF)();
// error C2159: more than one storage class specified
typedef static void (Person::*PPMF2)();
class Person
{
public:
static PPMF verificationFUnction()
{
return &Person::verifyAddress;
}
// error C2440: 'return' : cannot convert from
// 'void (__cdecl *)(void)' to 'PPMF2'
PPMF2 verificationFUnction2()
{
return &Person::verifyAddress2;
}
private:
void verifyAddress() {}
static void verifyAddress2() {}
};
int _tmain(int argc, _TCHAR* argv[])
{
Person scott;
PPMF pmf = scott.verificationFUnction();
(scott.*pmf)();
return 0;
}
Question: I need to define a function pointer PPMF2 to pointing to a static member function verifyAddress2. How can I do it?
#include "stdafx.h"
class Person;
typedef void (Person::*PPMF)();
typedef void (Person::*PPMF2)();
class Person
{
public:
static PPMF verificationFUnction()
{
return &Person::verifyAddress;
}
PPMF2 verificationFUnction2()
{
return &Person::verifyAddress2;
}
private:
void verifyAddress() {}
static void verifyAddress2() {}
};
int _tmain(int argc, _TCHAR* argv[])
{
Person scott;
PPMF pmf = scott.verificationFUnction();
(scott.*pmf)();
return 0;
}
A pointer to a static member function is just a normal function pointer. typedef void (*PPMF2)(). You assign it to a static member function like you assign any function pointer, only that the static member function is inside the class scope:
PPMF2 myfunc = &MyClass::StaticMemberFunc;
About static member function guarantees:
ะก++ ISO/IEC 14882 2003-10-15 says that
5.2.2 There are two kinds of function call: ordinary function call and member function 57) (9.3) call....
57) A static member function (9.4) is an ordinary function.
Theoretically static-member-functions can have another calling convention.
But standart allow us to leverage on such thing...
Answer:
typedef void (Person::*PPMF2)() => typedef void (*PPMF2)()
If the function is static it does not require a (implicit) this pointer to be invoked. Therefore, a pointer to a static member function is not the same as a member function pointer:
#include "stdafx.h"
class Person;
typedef void (Person::*PPMF)();
typedef /*static*/ void (*PPMF2)();
class Person
{
public:
static PPMF verificationFUnction()
{
return &Person::verifyAddress;
}
PPMF2 verificationFUnction2()
{
return &Person::verifyAddress2;
}
private:
void verifyAddress() {}
static void verifyAddress2() {}
};
int _tmain(int argc, _TCHAR* argv[])
{
Person scott;
PPMF pmf = scott.verificationFUnction();
(*pmf)();
return 0;
}
EDIT:
removed the offending static from the typedef.
#include<iostream>
using namespace std;
class A
{
private:
int x,y;
static int a;
public:
A()
{
x = 10;
y = 11;
}
~A()
{
}
void displayNonStatic()
{
cout<<x<<" "<<y<<endl;
}
void displayStatic()
{
cout<<a<<endl;
}
};
int A::a = 12;
int main()
{
typedef void (A::*NonStatic)(void);
typedef void (A::*Static)(void);
A a1;
NonStatic _nstatic = &A::displayNonStatic ;
Static _static = &A::displayStatic;
// Always make sure that call to the pointer to the member functions is made within the context of the instance.
//Correct way to call the pointer within the context of the instance " a1 " .
(a1.*_nstatic)();
(a1.*_static)();
//Error case given below, the pointer is not called within the context of the instance
// (*_nstatic)(); ->error
// (*_static)(); ->error
getchar();
}
Refer to the link for more information.