I'm a noob of c++, I'm trying to use a template function to get the private members inside a class because there are two types of parameters.
What I wrote is like:
template <typename Type>
Type const& Get(Type const& value)
{
return value;
}
class Event{
public:
Event(int const InputYear, int const InputMonth, int const InputDay, char const* InputContent, char const* InputNa me = "None")
:Year(InputYear), Month(InputMonth), Day(InputDay), Content(InputContent), Name(InputName)
{
}
~Event();
private:
int Year;
int Month;
int Day;
char* Content;
char* Name;
friend Type const& Get(Type const& value);
};
I don't know if my definition of friend is correct, if not could someone tell me how to use such template to access the private members?
The specification tells us that under certain circumstances (in this case explicit template instantiations), the usual access checking rules are not applied.
12 The usual access checking rules do not apply to names used to specify explicit instantiations. [ Note: In
particular, the template arguments and names used in the function declarator (including parameter types,
return types and exception specifications) may be private types or objects which would normally not be
accessible and the template may be a member template or member function which would not normally be
accessible. — end note ]
Thus, we can use this property to make a generic getter to a private member.
template <auto Event::* Member>
struct Getter {
friend auto &get(Event &e) { return e.*Member; }
};
template struct Getter<&Event::Year>;
auto &get(Event &e);
Event event{2021, 12, 24, "some event description"};
int year = get(event); // 2021
Related
export class Globals
{
static m_Name : string = "Hello world";
static m_Version : number = 1.0;
static m_Canvas : HTMLCanvasElement = null;
static m_Foo : Foo = null;
}
public OnDocumentLoad() : void
{
Globals.m_Canvas = <HTMLCanvasElement>document.getElementById('myCanvas');
Globals.m_Foo = new Foo(m_Name, m_Version);
}
Is this acceptable use of static in TypeScript? I'm unsure of what static is doing in this case other than making the member variables class members that everyone can access regardless of instance. But, for example, is m_Foo and m_Canvas valid instances within the Globals class, kind of like singletons so to speak (without any undefined checking and presumably anytime after OnDocumentLoad of course)
Originally I didn't have Globals as a class and they were just generic var declarations I had in a .ts file I was referencing everywhere. But I wanted to organize them into a nice little Globals class. This works in my experience testing it so far, but I wanted to see if there was anything I was missing about what static is doing here.
The most I found on the subject was here in the Specification:
http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf
Member declarations with a static modifier are called static member declarations. Static property
member declarations declare properties in the constructor function type (section 8.2.5), and must specify
names that are unique among all static property member declarations in the containing class, with the
exception that static get and set accessor declarations may pairwise specify the same name.
Note that the declaration spaces of instance and static property members are separate. Thus, it is possible
to have instance and static property members with the same name
From that I gleam that you can make an instance of Globals and its members will have a different meaning from just calling the Globals.m_Name for example, but I don't intend to do that here.
If you want to create a namespace object, use module:
export module Globals
{
export var m_Name : string = "Hello world";
export var m_Version : number = 1.0;
export var m_Canvas : HTMLCanvasElement = null;
export var m_Foo : Foo = null;
}
For my Data Structures class we've been asked to take a previously implemented balanced tree(from a prior project) and use it to implement parts of the C++ standard map class.
http://cplusplus.com/reference/stl/map/
I figured the most obvious first step was to template the entire class, allowing for separate key and storage types. Of course, I ran into problems with templating. Generally my templating works until I attempt to template a function that is using a local nested datatype "rbNode". If I include template parameters in the function definition, I get syntax errors. If I leave them out, I get "template parameters not included" errors.
This is the class implementation that gives me the errors in Visual Studio 2010 (errors listed below):
#include <cstdlib>
#include <iostream>
template <class key_type, class T>
class myMap
{
private:
//typedef pair<const key_type, T> value_type;
struct rbNode
{
//value_type ref;
int element;
rbNode * left;
rbNode * right;
bool red;
rbNode(int key)
{
left = NULL;
right = NULL;
//ref.first = key;
//ref.second = element;
element = key;
red = true;
}
};
rbNode * root;
bool search(int , rbNode *);
rbNode * LL_Rotation(rbNode *);
};
template <class key_type, class T>
myMap<key_type,T>::rbNode* myMap<key_type,T>::LL_Rotation(rbNode * curr) // errors occur on this line
{
rbNode * temp = curr->right;
curr->right = temp->left;
temp->left = curr;
curr->red = 1;
temp->red = 0;
return temp;
}
This function, however, compiles just fine with the above function commented out:
template <class key_type,class T>
bool myMap<key_type,T>::search(int key,rbNode * tree)
{
if(tree!=NULL)
if(tree->element==key)
return true;
else
if(key< tree->element)
return search(key,tree->left);
else
return search(key,tree->right);
else
return false;
}
In particular, I'm getting
missing ';' before '*'
and
missing type specifier - int assumed. Note: C++ does not support default-int
on the line the implementation for "LLRotation"'s name is in (pointed out in comment). I'm not very experienced with templating, so I get the feeling the I'm making a very stupid mistake. Regardless, if you need more of my code, or more information, let me know. Any help is greatly appreciated.
Note: I'm sure my code has plenty of bad practices, etc. in it. I'm still learning. Feel free to point them out, but I'm mostly concerned with the templating issues.
You're just missing a typename for the dependent name:
template <class key_type, class T>
typename myMap<key_type,T>::rbNode* myMap<key_type,T>::LL_Rotation(rbNode * curr)
^^^^^^^^
I'm working on a plug-in protocol of sorts. The idea is that there's a base clase PCOperatorBase and that plugins would subclass this base class to provide specific functionality through a "process" virtual method that they override. The subclasses also should have a static struct member that hold typical plugin info: plug name, type and subtype. This info is used by another class (a PCOperatorManager) to know what types of plugins is dealing with. And I thought about having it be a static member so that there's no need to instantiate a plug to merely find out about the type of operator it is.
I have the following classes:
PCOperatorBase.h the superclass from which to derive all other plugs:
#ifdef PCOPERATORBASE_EXPORTS
#define PCOPERATORBASE_API __declspec(dllexport)
#else
#define PCOPERATORBASE_API __declspec(dllimport)
#endif
class PCOPERATORBASE_API PCOperatorBase
{
public:
typedef struct OperatorInfo
{
wchar_t* name;
wchar_t* type;
wchar_t* subtype;
} OperatorInfo;
PCOperatorBase(void);
virtual ~PCOperatorBase(void);
virtual int process(int* inBuffer, int* outBuffer, int bufferSize);
};
And then, for instance, a subclass:
BlackNWhite.h: a RGB->black / white operator -- yes, these are going to be graphics plugs, and disregard the types for the in / out buffers.. they are merely placeholders at this point.
#ifdef BLACKNWHITE_EXPORTS
#define BLACKNWHITE_API __declspec(dllexport)
#else
#define BLACKNWHITE_API __declspec(dllimport)
#endif
// This class is exported from the BlackNWhite.dll
class BLACKNWHITE_API CBlackNWhite : PCOperatorBase
{
public:
static PCOperatorBase::OperatorInfo* operatorInfo;
CBlackNWhite(void);
virtual ~CBlackNWhite(void);
//virtual int process(int* inBuffer, int* outBuffer, int bufferSize);
};
BLACKNWHITE_API CBlackNWhite* getOperatorInstance();
BLACKNWHITE_API const PCOperatorBase::OperatorInfo* getOperatorInfo();
And here the implementation file:
BlackNWhite.cpp:
#include "stdafx.h"
#include "BlackNWhite.h"
BLACKNWHITE_API CBlackNWhite* getOperatorInstance()
{
return new CBlackNWhite();
}
BLACKNWHITE_API const PCOperatorBase::OperatorInfo* getOperatorInfo()
{
return CBlackNWhite::operatorInfo;
}
CBlackNWhite::CBlackNWhite()
{
}
CBlackNWhite::~CBlackNWhite()
{
}
Now, I've tried a few approaches but I can't get the DLL to compile, because of the static member.The linker throws:
\BlackNWhite.lib and object c:\Projects\BlackNWhite\Debug\BlackNWhite.exp
1>BlackNWhite.obj : error LNK2001: unresolved external symbol "public: static struct PCOperatorBase::OperatorInfo * CBlackNWhite::operatorInfo" (?operatorInfo#CBlackNWhite##2PAUOperatorInfo#PCOperatorBase##A)
1>c:\Projects\BlackNWhite\Debug\BlackNWhite.dll : fatal error LNK1120: 1 unresolved externals
I thought that since the struct is defined inside the base class and the base class is exporting, the struct would export too. But I guess I'm wrong?
So how should I be doing it?
And regardless, is there a better approach to having the plugs' factory export their name,type and subtype without the need for instantiation than a static class member? For example, a resource file? or even another extern "C" function could return this info.. But I just felt that since it's C++ it makes the most sense to encapsulate this data (which is about the class as a factory itself) within the class, whether through a member or a method.
It doesn't have anything to do with DLLs, you declared the static member but you forgot to define it. Add this line to BlackNWhite.cpp:
PCOperatorBase::OperatorInfo* CBlackNWhite::operatorInfo = NULL;
I'm currently start using boost::program_options for parsing command line options as well as configuration files.
Is it possible to use own template classes as option arguments? That means, something like
#include <iostream>
#include "boost/program_options.hpp"
namespace po = boost::program_options;
template <typename T>
class MyClass
{
private:
T* m_data;
size_t m_size;
public:
MyClass( size_t size) : m_size(size) { m_data = new T[size]; }
~MyClass() { delete[] m_data; }
T get( size_t i ) { return m_data[i]; }
void set( size_t i, T value ) { m_data[i] = value; }
};
int main (int argc, const char * argv[])
{
po::options_description generic("General options");
generic.add_options() ("myclass", po::value< MyClass<int>(2) >(),
"Read MyClass");
return 0;
}
Trying to compile this I get an Semantic Issue (No matching function for call to 'value'). I guess I need to provide some casting to an generalized type but I have no real idea.
Can anybody help?
Thanks
Aeon512
I wouldn't know if boost::program_options allows the use-case you are trying, but the error you are getting is because your are trying to pass an object as a template type to po::value<>. If the size is known at compile-time, you could have the size be passed in as a template parameter.
template< typename T, size_t size >
class MyClass {
T m_data[size];
public:
// ...
};
And then use it like so:
po::value< MyClass<int, 2> >()
You should also look into using Boost.Array instead that I guess fulfills what you are trying to implement.
I would write it like this:
MyClass<int> mine(2);
generic.add_options() ("myclass", po::value(&mine), "Read MyClass");
Then all that needs to be done is to define an input stream operator like this:
std::istream& operator >>(std::istream& source, MyClass& target);
Then Boost Program Options will invoke this stream operator when the myclass option is used, and your object will be automatically populated according to that operator's implementation, rather than having to later call one of the Program Options functions to extract the value.
If you don't prefer the above syntax, something like should work too:
generic.add_options() ("myclass", po::value<MyClass<int> >()->default_value(MyClass<int>(2)), "Read MyClass");
This way you would be creating the instance of your class directly with your desired constructor argument outside of the template part where runtime behavior isn't allowed. I do not prefer this way because it's verbose and you end up needing to call more functions later to convert the value.
When I write class templates, and need to fully-specialize members of those classes, Doxygen doesn't recognize the specialization - it documents only the generic definition, or (if there are only specializations) the last definition. Here's a simple example:
===MyClass.hpp===
#ifndef MYCLASS_HPP
#define MYCLASS_HPP
template<class T> class MyClass{
public:
static void foo();
static const int INT_CONST;
static const T TTYPE_CONST;
};
/* generic definitions */
template<class T>
void MyClass<T>::foo(){
printf("Generic foo\n");
}
template<class T>
const int MyClass<T>::INT_CONST = 5;
/* specialization declarations */
template<> void MyClass<double>::foo();
template<> const int MyClass<double>::INT_CONST;
template<> const double MyClass<double>::TTYPE_CONST;
template<> const char MyClass<char>::TTYPE_CONST;
#endif
=== MyClass.cpp ===
#include "MyClass.hpp"
/* specialization definitions */
template<>
void MyClass<double>::foo(){
printf("Specialized double foo\n");
}
template<> const int MyClass<double>::INT_CONST = 10;
template<> const double MyClass<double>::TTYPE_CONST = 3.141;
template<> const char MyClass<char>::TTYPE_CONST = 'a';
So in this case, foo() will be documented as printing "Generic foo," INT_CONST will be documented as set to 5, with no mention of the specializations, and TTYPE_CONST will be documented as set to 'a', with no mention of 3.141 and no indication that 'a' is a specialized case.
I need to be able to document the specializations - either within the documentation for MyClass<T>, or on new pages for MyClass<double>, MyClass<char>. How do I do this? Can Doxygen even handle this? Am I possibly doing something wrong in the declarations/code structure that's keeping Doxygen from understanding what I want?
I should note two related cases:
A) For templated functions, specialization works fine, e.g.:
/* functions that are global/in a namespace */
template<class T> void foo(){ printf("Generic foo\n"); }
template<> void foo<double>(){ printf("Specialized double foo\n"); }
This will document both foo<T>() and foo<double>().
B) If I redeclare the entire template, i.e. template<> class MyClass<double>{...};, then MyClass<double> will get its own documentation page, as a seperate class. But this means actually declaring an entirely new class - there is no relation between MyClass<T> and MyClass<double> if MyClass<double> itself is declared. So I'd have to redeclare the class and all its members, and repeat all the definitions of class members, specialized for MyClass<double>, all to make it appear as though they're using the same template. Very awkward, feels like a kludge solution.
Suggestions? Thanks much :)
--Ziv
Further seeking indicates that this issue was an open bug, fixed in Doxygen 1.8.10.
This bug appears to be fixed 3 weeks ago