Is it possible to enable, disable class member functions?
Situation:
I have a class with 2 types. Each Type has a own constructor. One Type need a function which must not have the other Type.
Example:
class A {
enum struct TypeEnum : int {
TYPE_1 = 1,
TYPE_2 = 2
};
const TypeEnum type;
int x;
A(void) : type(TypeEnum::TYPE_1) { }
A(int _x) : type(TypeEnum::TYPE_2) {
x = _x;
}
// function only for Type 2
void A::operator += (const int& n) {
x = x + n;
}
};
int main() {
A test1 = new A();
A test2 = new A(1);
test1 += 5; // compiler error should be here
test2 += 5; // OK
return 0;
}
Is where something possible like this:
class A {
enum struct TypeEnum : int {
TYPE_1 = 1,
TYPE_2 = 2
};
const TypeEnum type;
int x;
A(void) : type(TypeEnum::TYPE_1) { }
A(int _x) : type(TypeEnum::TYPE_2) {
x = _x;
}
// Is somethig like this realy impossible
void A::operator += (const int& n) -> enable_if(type == TypeEnum::Type2) { // if not compile error
x = x + n;
}
};
You can use specialization:
enum struct TypeEnum : int {
TYPE_1 = 1,
TYPE_2 = 2
};
template<TypeEnum Type>
class A;
template<>
class A<TypeEnum::TYPE_1>
{
public:
A(void) { }
};
template<>
class A<TypeEnum::TYPE_2>
{
public:
A(int _x) {
x = _x;
}
int x;
void operator += (const int& n) {
x = x + n;
}
};
int main() {
A<TypeEnum::TYPE_1> test1;
A<TypeEnum::TYPE_2> test2{1};
test1 += 5; // compiler error should be here
test2 += 5; // OK
return 0;
}
Maybe following may help:
class A {
public:
explicit A(TypeEnum type) : type(type) {}
virtual ~A() {}
protected:
enum struct TypeEnum : int {
TYPE_1 = 1,
TYPE_2 = 2
};
const TypeEnum type;
};
class B : public A{
public:
B() : A(TYPE_1) {}
};
class C : public A{
public:
explicit C(int x) : A(TYPE_2), x(x) {}
C& operator += (int n) { x = x + n; }
private:
int x;
};
inheritance is here to reflect your case with a common type. it is not required else.
A thing you can do anyway:
B make_A() { return B{}; }
C make_A(int x) { return C{x}; }
int main() {
auto test1 = make_A(); // B
auto test2 = make_A(1); // C
test1 += 5; // compiler error should be here
test2 += 5; // OK
return 0;
}
Strange that you didn't get compilation error here:
// function only for Type 2
void A::operator += (const int& n) {
x = x + n;
}
I thought you wanted something like:
// function only for Type 2
A& operator += (int n) {
x = x + n;
return *this;
}
Answering on your question - C++ doesn't work like this. Nevertheless you can implement something similar with templates but I suggest not to do it unless it's just a test program.
Related
I need to create a queue of different class objects (These classes are not related). I found a solution as follows:
Create a base class and use polymorphism.
Here is how I implemented it,
class Task {
public:
virtual void operator()() {
printf("should not be called\n");
}
};
class TaskRPCB : public Task {
private:
int x;
// other varibles
std::function<void(int)> func;
public:
TaskRPCB(std::function<void(int)>&f , int x) {
this->func = f;
this->x = x;
}
void operator()() {
printf("TaskRPCB function is executing...\n");
func(x);
}
};
class TaskECB : public Task {
private:
// other varibles
std::function<void(void)> func;
public:
TaskECB(std::function<void(void)>&f) : func(f) {}
void operator()() {
printf("TaskECB function is executing...\n");
func();
}
};
void F1() { // dummy function for example
cout <<"no x"<<endl;
}
void F2(int x) { // dummy function for example
cout <<"x : "<<x<<endl;
}
int main() {
queue<unique_ptr<Task>> Q;
function<void()> func1 = F1;
function<void(int)> func2 = F2;
TaskECB task1(func1);
TaskRPCB task2(func2,4);
Q.emplace(new TaskECB(func1));
Q.emplace(new TaskRPCB(func2,4));
(*Q.front())();
Q.pop();
(*Q.front())();
Q.pop();
}
The problem is, I can not push the objects directly as shown above. I have to create an object of an inherited class and pass it to another function to do the push action. It is because ( in my case ) the queue is a part of a thread-safe queue and it has separate Push() method.
template<typename T>
void threadSafeQueue<T>::Push(T newData) { /* TODO: size check before pushing */
std::shared_ptr<T> data(std::make_shared<T>(std::move(newData)));
/* construct the object before lock*/
std::lock_guard<std::mutex> lk(mut);
taskQueue.push(data);
dataCond.notify_one();
}
Earlier I did not have multiple tasks to execute ( or push ) into the queue, therefore
threadSafeQueue<TaskRPCB> workQ declaration worked fine for me.
Creating a base Task class like above is not working because of object slicing
Can you suggest other ways to store objects in the queue ( so that I can still use the lock guarded Push() method )
Thanks !
update :
is the correct way of using variant?
typedef std::variant<TaskECB, TaskRPCB> myType;
int main() {
queue<unique_ptr<myType>> Q;
function<void()> func1 = F1;
function<void(int)> func2 = F2;
TaskECB task1(func1);
TaskRPCB task2(func2,4);
myType x = task1;
Q.push(make_unique<myType>(x));
x = task2;
Q.push(make_unique<myType>(x));
if((*Q.front()).index() == 0) {
auto f1 = get<TaskECB>(*Q.front());
f1();
Q.pop();
}
if((*Q.front()).index() == 1) {
auto f1 = get<TaskRPCB>(*Q.front());
f1();
Q.pop();
}
}
update2:
using myVariantType = std::variant<TaskECB, TaskRPCB>;
struct VisitPackage {
void operator()(TaskECB & task) {
task();
}
void operator()(TaskRPCB& task) {
task();
}
};
int main() {
queue<myVariantType> Q;
function<void()> func1 = F1;
function<void(int)> func2 = F2;
TaskECB task1(func1);
TaskRPCB task2(func2,4);
Q.emplace(task1);
Q.emplace(task2);
std::visit(VisitPackage(), Q.front());
Q.pop();
std::visit(VisitPackage(), Q.front());
Q.pop();
}
Here is my insert method of a chaining class that I implement, the data type is integer (typedef int TELEM).By displaying the numbers stored, from 16 shows me other values too big
include
typedef int TELEM;
// liste d'éléments de type TELEM
class liste {
public:
liste::liste() : m_nb(0) ,m_tetefile(0)
{
m_tetefile = new TELEM[m_nb+1] ;
}
liste::~liste()
{
m_nb = 0;
delete m_tetefile;
}
bool liste::est_vide() const
{
return m_nb == 0;
}
int liste::taille() const
{
return m_nb;
}
const TELEM& liste::operator[](int i) const
{
assert((i>=1) && (i<=m_nb));
return (m_tetefile[i]);
}
void liste::inserer(const TELEM& e, int i)
{
assert((i>=1) && (i<=m_nb+1));
for (int k = m_nb ; k >= i ; --k)
m_tetefile[k+1] = m_tetefile[k];
m_tetefile[i] = e;
std::cout << e <<std::endl;
std::cout << m_tetefile[i] <<std::endl;
m_nb++;
}
private:
TELEM m_nb ;
TELEM *m_tetefile;
};
std::ostream& operator<<(std::ostream& os, const liste& l)
{
os << '(';
if (!l.est_vide())
os << l[1];
for (int i=2; i<=l.taille(); ++i)
os << ',' << l[i];
os << ')';
return os;
}
from 16 ca gives me this
(2,4,6,8,10,12,14,875311656,942421548,741355820)
instead
(2,4,6,8,10,12,14,16,18,20)
I am trying to implement a vector using my own class so I can not do the initialiser list part
# include <iostream>
# include <exception>
# include<initializer_list>
template <class T>
class vector {
public:
T* a;
T n;
int pos, c;
vector() { a = 0; n = 0; }
vector(T n) : n(n) { a = new T[n]; }
vector(std::initializer_list <vector> l) {
a = new T[int(sizeof(l))];
for (int f : l)
*(a + f) = l.begin() + f;
}
void push_back(T k) {
int i = k;
*(a + n) = k;
}
vector& operator= (vector&& th) {
this->a = th.a;
th.a = nullptr; return (*this);
}
vector& operator=(vector& k)
{
this->a = k.a;
return(*this);
}
int size() { return n; }
void pop_back() { *(a + n) = nullptr;
n--;
}
void resize(int c) {
delete a;
n = c;
a = new T[c];
}
T operator[](int pos) {
if (pos > sizeof(a))
std::cout << "out of range";
else return *(a + pos);
}
};
int main() {
vector<int> a(10);
vector<char>b{ 'w','b','f','g' };
getchar();
return 0;
}
I am just trying to use pointer offset notation to take the initializer list items into the dynamic array but I get errors VS 17 IDE
Severity Code Description Project File Line Suppression
Error C2440 '=': cannot convert from 'const _Elem *' to 'T'
Error C2440 'initializing': cannot convert from 'const _Elem' to 'int'
Hello Nimrod!
#include <iostream>
#include <exception>
#include <initializer_list>
// normally people don't place a space between '#' and 'include'
template <class T>
class vector {
public:
T* a;
int n;
// probably it is length the vector
// change T to int
int pos, c;
vector() {
a = nullptr;
// do not use '0' to instruct null pointer
n = 0;
}
vector(int n): n(n) { a = new T[n]; }
vector(std::initializer_list<T> l) {
a = new T[l.size()];
// redundant force cast from size_t to int
for (int i = 0; i < l.size(); i++) {
a[i] = l.begin()[i];
}
// for (int f : l) # it seems that you wrote JavaScript before?
// *(a + f) = l.begin() + f;
}
void push_back(T k) {
// assigns "T k" to "int i"? it's confusing
// int i = k;
// *(a + n) = k;
}
// probably still many problems
vector& operator=(vector&& th) {
this->a = th.a;
th.a = nullptr;
return (*this);
}
vector& operator=(vector& k) {
this->a = k.a;
return(*this);
}
int size() { return n; }
void pop_back() { *(a + n) = nullptr;
n--;
}
void resize(int c) {
delete a;
n = c;
a = new T[c];
}
T operator[](int pos) {
if (pos > sizeof(a))
std::cout << "out of range";
else return *(a + pos);
}
};
int main() {
vector<int> a(10);
vector<char>b{ 'w','b','f','g' };
getchar();
return 0;
}
You still need more practice. XP
In your context of code, template variable for initializer_list should be T rather than int.
Range for loop with initializer_list<T> will fetch the values
in the list. Therefore it should belong to T.
The common "solution" to use GetProcAddress with C++ is "extern "C", but that breaks overloading. Name mangling allows multiple functions to co-exist, as long as their signature differs. But is there a way to find these mangled names for GetProcAddress?
The VC++ compiler knows its own name mangling scheme, so why not use that? Inside template<typename T> T GetProcAddress(HMODULE h, const char* name), the macro __FUNCDNAME__ contains the mangled name of GetProcAddress. That includes the T part. So, inside GetProcAddress<void(*)(int), we have a substring with the mangled name of void(*)(int). From that, we can trivially derive the mangled name of void foo(int);
This code relies on the VC++ macro __FUNCDNAME__. For MinGW you'd need to base this on __PRETTY_FUNCTION__ instead.
FARPROC GetProcAddress_CppImpl(HMODULE h, const char* name, std::string const& Signature)
{
// The signature of T appears twice in the signature of T GetProcAddress<T>(HMODULE, const char*)
size_t len = Signature.find("##YA");
std::string templateParam = Signature.substr(0, len);
std::string returnType = Signature.substr(len+4);
returnType.resize(templateParam.size()); // Strip off our own arguments (HMODULE and const char*)
assert(templateParam == returnType);
// templateParam and returnType are _pointers_ to functions (P6), so adjust to function type (Y)
std::string funName = "?" + std::string(name) + "##Y" + templateParam.substr(2);
return ::GetProcAddress(h, funName.c_str());
}
template <typename T>
T GetProcAddress(HMODULE h, const char* name)
{
// Get our own signature. We use `const char* name` to keep it simple.
std::string Signature = __FUNCDNAME__ + 18; // Ignore prefix "??$GetProcAddress#"
return reinterpret_cast<T>(GetProcAddress_CppImpl(h, name, Signature));
}
// Showing the result
struct Dummy { };
__declspec(dllexport) void foo( const char* s)
{
std::cout << s;
}
__declspec(dllexport) void foo( int i, Dummy )
{
std::cout << "Overloaded foo(), got " << i << std::endl;
}
__declspec(dllexport) void foo( std::string const& s )
{
std::cout << "Overloaded foo(), got " << s << std::endl;
}
__declspec(dllexport) int foo( std::map<std::string, double> volatile& )
{
std::cout << "Overloaded foo(), complex type\n";
return 42;
}
int main()
{
HMODULE h = GetModuleHandleW(0);
foo("Hello, ");
auto pFoo1 = GetProcAddress<void (*)( const char*)>(h, "foo");
// This templated version of GetProcAddress is typesafe: You can't pass
// a float to pFoo1. That is a compile-time error.
pFoo1(" world\n");
auto pFoo2 = GetProcAddress<void (*)( int, Dummy )>(h, "foo");
pFoo2(42, Dummy()); // Again, typesafe.
auto pFoo3 = GetProcAddress<void (*)( std::string const& )>(h, "foo");
pFoo3("std::string overload\n");
auto pFoo4 = GetProcAddress<int (*)( std::map<std::string, double> volatile& )>(h, "foo");
// pFoo4 != NULL, this overload exists.
auto pFoo5 = GetProcAddress<void (*)( float )>(h, "foo");
// pFoo5==NULL - no such overload.
}
Use dumpbin /exports 'file.dll' to get the decorated / undecorated name of all the symbols.
It's impossible to do it just by using GetProcAddress. However, one way to do it would be to enumerate all the exported functions for that particular module, and do a pattern matching to find all the mangled names.
More specifically, refer to this answer here. The only change you will need to make would be to pass in TRUE for MappedAsImage parameter and the return value of GetModuleHandle for Base parameter to ImageDirectoryEntryToData function call.
void EnumerateExportedFunctions(HMODULE hModule, vector<string>& slListOfDllFunctions)
{
DWORD *dNameRVAs(0);
_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory;
unsigned long cDirSize;
_LOADED_IMAGE LoadedImage;
string sName;
slListOfDllFunctions.clear();
ImageExportDirectory = (_IMAGE_EXPORT_DIRECTORY*)
ImageDirectoryEntryToData(hModule,
TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &cDirSize);
if (ImageExportDirectory != NULL)
{
dNameRVAs = (DWORD *)ImageRvaToVa(LoadedImage.FileHeader,
LoadedImage.MappedAddress,
ImageExportDirectory->AddressOfNames, NULL);
for(size_t i = 0; i < ImageExportDirectory->NumberOfNames; i++)
{
sName = (char *)ImageRvaToVa(LoadedImage.FileHeader,
LoadedImage.MappedAddress,
dNameRVAs[i], NULL);
slListOfDllFunctions.push_back(sName);
}
}
}
I can't quite fathom why you'd ever want/need a constexpr version of MSalters' solution, but here it is, complete with namespace mangling. Use as
using F = int(double*);
constexpr auto f = mangled::name<F>([]{ return "foo::bar::frobnicate"; });
constexpr const char* cstr = f.data();
where F is the function signature and foo::bar::frobnicate is the (possibly qualified) name of the function.
#include<string_view>
#include<array>
namespace mangled
{
namespace detail
{
template<typename F>
inline constexpr std::string_view suffix()
{
auto str = std::string_view(__FUNCDNAME__);
return str.substr(14, str.size() - 87);
}
template<typename L>
struct constexpr_string
{
constexpr constexpr_string(L) {}
static constexpr std::string_view data = L{}();
};
template<typename Name>
inline constexpr int qualifiers()
{
int i = -2, count = -1;
while(i != std::string_view::npos)
{
i = Name::data.find("::", i + 2);
count++;
}
return count;
}
template<typename Name>
inline constexpr auto split()
{
std::array<std::string_view, qualifiers<Name>() + 1> arr = {};
int prev = -2;
for(int i = arr.size() - 1; i > 0; i--)
{
int cur = Name::data.find("::", prev + 2);
arr[i] = Name::data.substr(prev + 2, cur - prev - 2);
prev = cur;
}
arr[0] = Name::data.substr(prev + 2);
return arr;
}
template<typename F, typename Name>
struct name_builder
{
static constexpr auto suf = detail::suffix<F>();
static constexpr auto toks = split<Name>();
static constexpr auto len = Name::data.size() + suf.size() - toks.size() + 6;
static constexpr auto str = [] {
std::array<char, len> arr = {};
arr[0] = '?';
int i = 1;
for(int t = 0; t < toks.size(); t++)
{
if(t > 0)
arr[i++] = '#';
for(auto c : toks[t])
arr[i++] = c;
}
arr[i++] = '#';
arr[i++] = '#';
arr[i++] = 'Y';
for(auto c : suf)
arr[i++] = c;
return arr;
}();
};
}
template<typename F, typename LambdaString>
inline constexpr std::string_view name(LambdaString)
{
using Cs = detail::constexpr_string<LambdaString>;
using N = detail::name_builder<F, Cs>;
return {N::str.data(), N::len};
}
}
GodBolt
Is it possible to embed a structure of varying type inside another structure in C?
Basically I want to do something like this.
struct A { int n; void *config; }
struct AConfig { int a; char *b; }
struct BConfig { int a; float b; }
const struct A table[] = {
{ 103, (void*)(struct AConfig){ 1932, "hello" } },
{ 438, (void*)(struct BConfig){ 14829, 33.4f } }
}
Is this possible in C or do I have to define the structures separately?
No, it doesn't work like that. You need explicit storage for each structure:
struct A { int n; void *config; };
struct AConfig { int a; char *b; };
struct BConfig { int a; float b; };
struct AConfig ac = { 1932, "hello" };
struct BConfig bc = { 14829, 33.4f };
const struct A table[] = {
{ 103, &ac },
{ 438, &bc }
};
Edit:
Another possibility is to utilize a union and C99 (-std=c99) named initializers:
enum config_type { CT_INT, CT_FLOAT, CT_STRING };
union config_value {
int int_value;
float float_value;
const char* string_value;
};
struct config {
enum config_type ctype;
union config_value cvalue;
};
struct config sys_config[] = {
{ CT_INT, { .int_value = 12 }},
{ CT_FLOAT, { .float_value = 3.14f }},
{ CT_STRING, { .string_value = "humppa" }}};
void print_config( const struct config* cfg ) {
switch ( cfg->ctype ) {
case CT_INT:
printf( "%d\n", cfg->cvalue.int_value ); break;
case CT_FLOAT:
printf( "%f\n", cfg->cvalue.float_value ); break;
case CT_STRING:
printf( "%s\n", cfg->cvalue.string_value ); break;
default:
printf( "unknown config type\n" );
}
}
You can use a union:
struct AConfig { int a; char *b; };
struct BConfig { int a; float b; };
struct A {
int n;
union {
struct AConfig a;
struct BConfig b;
};
};
Note that a and b are in the exact same space in memory. So if you are going to use the A.a you should not use A.b and vice versa.
Since this is an anonymous union, you can reference both a and b as if they were direct fields of struct A:
struct A sa;
sa.n = 3;
sa.b.a = 4;
sa.b.b = 3.14;
It would work if BConfig had a float pointer to b.
By the way, maybe you need to refactor your code to fit to C syntax.
#include <stdio.h>
#include <stdlib.h>
typedef struct { int n; void *config; } Config;
typedef struct { int a; char *b; } AConfig;
typedef struct { int a; float *b; } BConfig;
int main(void) {
AConfig A;
BConfig B;
A.a= 103;
A.b= "hello";
B.a= 438;
B.b=(float *) malloc (sizeof(float));
*(B.b)= 33.4f;
const Config table[] = {
{ A.a, (void *) A.b },
{ B.a, (void *) B.b }
};
printf("Hi\n");
return 0;
}
You may prefer a union. My union syntax is a little rusty, but something like this:
union config { char* c; float d; };
struct A {int n; int a; union config b;};
const struct A table[] = {
{103, 1932, { .c = "hello" } },
{14829, 438, { .d = 33.4f } }
};
You need C99 for the designated initalizer (the .c or .d in the table), and obviously some way to tell if you're accessing a char* or a float, but I assume you have that covered somewhere else.