Initialize static variable inside the header file using template - c++

Initialization of a static variable at the header file by using the templates (Used c++11, the 'inline' approach not supported)
cat base_class.hpp
#include <string>
#ifndef PROGRAM_BASE
#define PROGRAM_BASE
template <typename T>
struct S
{
static std::string s_elfName;
};
template <typename T>
std::string S<T>::s_elfName; //static initialization
class program_base : public S<void>{
public:
static std::string GetElfName() { return S<std::string>::s_elfName; }
bool update_string();
};
#endif
cat base_class.cpp
#include "base_class.hpp"
bool program_base::update_string(){
S<std::string>::s_elfName = "UpdateString";
}
cat read_string.cpp
#include <iostream>
#include "base_class.hpp"
using namespace std;
int main () {
program_base pb; pb.update_string();
cout << program_base::GetElfName() << endl;
}
The above one works fine, When I try to add templet inside the "class program_base"
cat base_class.hpp
#include <string>
#ifndef PROGRAM_BASE
#define PROGRAM_BASE
class program_base {
public:
template <typename T>
struct S
{
static std::string s_elfName;
};
template <typename T>
std::string S<T>::s_elfName; //static initialization
static std::string GetElfName() { return S<std::string>::s_elfName; }
bool update_string();
};
#endif
it's giving an error as " error: member 's_elfName' declared as a template"
Why I'm not able to declare a template inside the class instead of inheriting it?

As stated in the C++ Std. Nested class declaration:
Member functions and static data members of a nested class can be defined in a namespace scope enclosingthe definition of their class.
[Example:
struct enclose {
struct inner {
static int x;
void f(int i);
};
};
int enclose::inner::x = 1;
void enclose::inner::f(int i) { /* ... */ }
— end example]
If you take the definition out of outer class then it should be fine:
template <typename T>
std::string program_base::S<T>::s_elfName;
Since C++17 you can also do inline static initializing:
class program_base {
public:
template <typename T>
struct S
{
inline static std::string s_elfName;
};
static std::string GetElfName() { return S<std::string>::s_elfName; }
bool update_string();
};

Related

Defining a template specialization in an anonymous namespace (and compile error C2888)

Nutshell version: Why can't I define a template specialization (of a std-lib type) that's only useful in the current compilation unit in an anonymous namespace inside that compilation unit / cpp file?
Longer version:
I have a type that's only a quick helper inside one cpp file, let's call it struct Helper. Because it's only used in that compilation unit, it's declared and defined in an anonymous namespace inside the cpp.
Because I want an std::unordered_set<Helper>, I have to specialize std::hash. When I now try to define it inside the same anonymous namespace, I get a C2888 'std::hash<'anonymous-namespace'::Helper>': symbol cannot be defined within namespace 'anonymous-namespace'. Why is that?
I tried adding a using namespace std and similar things inside the AN, too, but to no avail.
/* This doesn't work */
namespace
{
struct Helper
{
int member1;
bool member2;
};
using namespace std;
template<>
struct std::hash<Helper>
{
size_t operator()(const Helper& helper) const
{
return 12345; /* how it's really generated is irrelevant here */
}
};
}
Of course, I can just put the specialization outside the AN, and it works. I just want to understand why it doesn't while it's inside it!
/* This works, but why doesn't the other? */
namespace
{
struct Helper
{
int member1;
bool member2;
};
}
template<>
struct std::hash<Helper>
{
size_t operator()(const Helper& helper) const
{
return 12345; /* how it's really generated is irrelevant here */
}
};
A symbol belonging to namespace std must be defined in a namespace that encloses std which means that you'll have to define it in the global namespace.
Here's an example from C2888:
namespace M {
namespace N {
void f1();
void f2();
}
void N::f1() {} // OK: namspace M encloses N
}
namespace O {
void M::N::f2() {} // C2888 namespace O does not enclose M
}
[temp.expl.spec/9] from the C++20 draft:
A template explicit specialization is in the scope of the namespace in which the template was defined. [ Example:
namespace N {
template<class T> class X { /* ... */ };
template<class T> class Y { /* ... */ };
template<>
class X<int> { /* ... */ }; // OK: specialization in same namespace
template<>
class Y<double>; // forward-declare intent to specialize for double
}
template<>
class N::Y<double> { /* ... */ }; // OK: specialization in enclosing namespace
template<>
class N::Y<short> { /* ... */ }; // OK: specialization in enclosing namespace
— end example ]

namespace specialization in template class

I have two different namespaces that implement identical methods and classes in two different ways. I am writing a class that used this methods and classes to do something, I was wondering if there was a way to declare the namespace without partial specialization as below:
#include <string>
#include <iostream>
namespace one
{
int test()
{
return 1;
}
}
namespace two
{
int test()
{
return 2;
}
}
enum names : int
{
first = 1,
second = 2
};
template <names>
struct base_class;
template <>
struct base_class<names::first>
{
using namespace ::one;
};
template <>
struct base_class<names::second>
{
using namespace ::two;
};
template <names ns>
struct delcare_namespace : public base_class<ns>
{
delcare_namespace()
{
std::cout << test() << "\n";
}
};
for the code above, I get
test’ was not declared in this scope
using namespace is not allowed in class scope, nor is namespace alias. I don't think you can do a specialization that would somehow inject the namespace.
It's not exactly the same, but if it's an option to declare all the functions you need from that namespace in the specialization, you can make the function pointer as a member of that specialization:
template <names>
struct base_class;
template <>
struct base_class<names::first>
{
static constexpr auto test = &one::test;
};
template <>
struct base_class<names::second>
{
static constexpr auto test = &two::test;
};
template <names ns>
struct delcare_namespace : public base_class<ns>
{
delcare_namespace()
{
std::cout << this->test() << "\n";
}
};
I was wondering if there was a way to declare the namespace
Unfortunately, I don't think it's possible inside a class/struct and inheriting it.
is there a work-around for this ?
The best I can imagine (if you can heavily modify your code) is transform your two namespaces in two different classes or structs, so the functions become methods (maybe static methods)
struct baseOne // former namespace one
{
static int test ()
{ return 1; }
};
struct baseTwo // former namespace two
{
static int test ()
{ return 2; }
};
so you can pass the base class (former namespace) as template parameter and inherit from it
template <typename B>
struct foo : public B
{
foo ()
{ std::cout << B::test() << "\n"; }
};
The following is a full working example
#include <string>
#include <iostream>
struct baseOne // former namespace one
{
static int test ()
{ return 1; }
};
struct baseTwo // former namespace two
{
static int test ()
{ return 2; }
};
template <typename B>
struct foo : public B
{
foo ()
{ std::cout << B::test() << "\n"; }
};
int main ()
{
foo<baseOne> f1; // print 1
foo<baseTwo> f2; // print 2
}
If the use of the B:: before the method names is annoying for you, you can transform the static methods inside the bases structs in ordinary methods or add directives as
using B::test;
inside foo.

How to use std::function as a template

I am new to the std::function concept.
I need to use std::function in following way
I have a class as follows
class A(string ,bool, string, std::function<void()>)
here the std::function<void()> should take different parameters from different objects.
The parameters will be basically different types of enumerations
for example
1)A a(string ,bool, string, std::function<void(enum xyz)>)
2)A b(string ,bool, string, std::function<void(enum abc)>)
3)A c(string ,bool, string, std::function<void(enum efg)>)
I want to know how should i structure the std::function in class A so that i can pass different enumerations as parameter to the class A objects
You can pass a template type as the std::function parameter. Here's an example:
#include <iostream>
#include <functional>
#include <string>
template <class T>
class Foo
{
public:
Foo(std::function<void(T)> f) : f_{f} {}
void call(T in) { f_(in); }
private:
std::function<void(T)> f_;
};
int main()
{
Foo<double> fd{[] (double d) { std::cout << d << '\n'; }};
fd.call(34.2);
Foo<std::string> fs{[] (std::string s) { std::cout << s << '\n'; }};
fs.call("Test!");
return 0;
}
Output:
34.2
Test!
After looking at your question, this is how you need to use the function.
#include <iostream>
#include <string>
#include <functional> //Need to include for std::function use
using namespace std;
//Declare the ENUM here.
enum ePat {xyz=1,abc,efg,mno};
enum ePat_second {def=1,ghi,jkl,opq};
//utility function you want to pass to std function
template <typename T>
void print(T e)
{
}
template <typename T>
class A
{
public:
//Constructore with std function as one of the argument
A(string ,bool , string, std::function<void(T)>)
{
}
};
int main()
{
//Declare your std function types.
std::function<void(ePat)> xyz_display = print<ePat>;
std::function<void(ePat_second)> def_display = print<ePat_second>;
//Pass it to the object.
A<ePat> a("abc" ,true, "abc",xyz_display);
A<ePat_second> b("def" ,true, "def",def_display);
}

How to pretty print the name of a template parameter at compile time

The question is rather simple: how to pretty print the name of a template parameter in a C++ class and assign it to a class variable at compile time ?
It seems that both typeinfo (typeid) and boost::typeindex must be evaluated at runtime or as least some part of them. This apparently does not allow the compiler to completely solve a constexpr containing a call to one of this function.
template<typename T>
class X
{
public:
static const char * name = /* SOME C++ code transforming T in a string (either std::string or char */
};
What am I missing ?
Is it only possible to generate a name at runtime ? In that case, does I really need an instantiated object ? It doesn't seem right to me, because the following perfectly work without any instance:
#include <iostream>
#include <string>
#include <boost/type_index.hpp>
using namespace std;
template<class T>
class X
{
public:
static std::string name()
{
return boost::typeindex::type_id<T>().pretty_name();
}
};
struct foobar {};
int main()
{
cout << X<int>::name() << endl;
cout << X<foobar>::name()<< endl;
}
So instead of having name() as a class method, I'd like to have it as a class variable.
I think, it is possible to use custom Type Traits. Please see the next example:
#include <iostream>
#include <string>
using namespace std;
//Using stub type traits
template <class T>
struct TypeTraits;
//your TypeTraits for specific types...
template<>
struct TypeTraits<int>
{
constexpr static const char *name = "int";
};
template<class T>
class X
{
public:
constexpr static const char * name = TypeTraits<T>::name;
};
struct foobar {};
//TypeTraits for custom foobar
template<>
struct TypeTraits<foobar>
{
constexpr static const char *name = "foobar";
};
int main()
{
//Now you can use static member here
cout << X<int>::name << endl;
cout << X<foobar>::name<< endl;
}
Also TypeTraits can be used (and expanded) for other purposes.

How can I perform different actions for different template parameters in a template class?

If I want to make a template class, and depending on the typeid of the template parameter perform different actions, then how do I code this?
For instance, I have the following template class, in which I want to initialize the member field data depending on whether it is an int or a string.
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
};
// Implementation of constructor
template <class T>
A<T>::A()
{
if (typeid(T) == typeid(int))
{
data = 1;
}
else if (typeid(T) == typeid(std::string))
{
data = "one";
}
else
{
throw runtime_error("Choose type int or string");
}
}
This code would not compile however, with the following main file.
#include "stdafx.h"
#include "A.h"
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
A<int> one;
return 0;
}
The error is: error C2440: '=' : cannot convert from 'const char [2]' to 'int', which means the code is actually checking the else-if statement for an int, even though it will never be able to reach that part of the code.
Next, following this example (Perform different methods based on template variable type), I tried the following A.h file, but I got several linker errors mentioning that A(void) is already defined in A.obj.
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
~A();
};
// Implementation of constructor
template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
Does anybody know how to get this code up and running? I also realize that using such an if-else statement in a template class might remove the power from a template. Is there a better way to code this?
EDIT: after discussion with Torsten (below), I now have the following A.h file:
#pragma once
#include <string>
// Class definition
template <class T>
class A
{
public:
A();
~A();
private:
T data;
};
// Implementation of initialization
template < class T >
struct initial_data
{
static T data() { throw runtime_error("Choose type int or string"); }
};
template <>
struct initial_data< int >
{
static int data() { return 1; }
};
template <>
struct initial_data< std::string >
{
static std::string data() { return "one"; }
};
// Definition of constructor
template <class T>
A<T>::A()
: data( initial_data< T >::data() )
{
}
and the following main:
#include "stdafx.h"
#include "A.h"
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
A<int> ione;
return 0;
}
The linker error I now get is: Test template 4.obj : error LNK2019: unresolved external symbol "public: __thiscall A::~A(void)" (??1?$A#H##QAE#XZ) referenced in function _wmain
Explicit specializations are the way to go.
I assume that you are including your A.h in several .cpp, and that's the root cause of your problem.
Specializations are definitions and there must be only one definition of A::A() and A::A() and so they must be in only one .cpp.
You'll have to move the explicit specialization in a .cpp
template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
and keep a declaration for them in A.h
template<> A<int>::A();
template<> A<std::string>::A();
so that the compiler knows they are explicitly specialized and doesn't try to add automatic one.
Edit: with these four files, g++ m.cpp f.cpp a.cpp doesn't show any errors.
// a.h
#define A_H
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
};
template<> A<int>::A();
template<> A<std::string>::A();
#endif
// a.cpp
#include "a.h"
template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
// f.cpp
#include "a.h"
int f()
{
A<int> one;
A<std::string> two;
}
// m.cpp
#include "a.h"
int f();
int main()
{
A<int> one;
A<std::string> two;
f();
}
You are correct in the second solution, what you need is template specialisation (keeping declaration and implementation together):
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
~A();
};
template <>
class A <std::string>
{
private:
std::string data;
public:
A() { data = "one"; }
};
template <>
class A <int>
{
private:
int data;
public:
A() { data = 1; }
};
If I may suggest a more elegant solution, then I would add a parameter to the constructor and avoid the template specialisation:
template <class T>
class A
{
private:
T data;
public:
A( T value ) : data( value ) {}
virtual ~A() {}
};
In case it's just the c'tor where you want to have behavior that depends on T, I would suggest to factor this out to a different struct:
template < class T >
struct initial_data
{
static T data() { throw runtime_error("Choose type int or string"); }
};
template <>
struct initial_data< int >
{
static int data() { return 1; }
}
template <>
struct initial_data< std::string >
{
static std::string data() { return "1"; }
}
If you specialize a class on it's template parameter, the different specializations are totally different types and can have different sets of data and functions.
Finally:
template <class T>
A<T>::A()
: data( initial_data< T >::data() )
{
}
kind regards
Torsten