C++ Function pointer wrapper throwing error when invoking - c++

I've been having some trouble recently with an invoker class I've created. Reason is so I can parse an address through the class constructor and have it handle calling methods that are in memory. Problem is, when I go to return a class object type, it throws an error "Cannot convert from std::string to InvokerType". Any help is appreciated.
template <class InvokerType>
class Invoker {
public:
Invoker(std::intptr_t address) :
address(address)
{ }
template<class... Arguments>
InvokerType invoke(Arguments&&... parameters) {
InvokerType func = (InvokerType)this->address;
return (InvokerType)func(std::forward<Arguments>(parameters)...);
}
private:
std::intptr_t address;
};
std::string test(const std::string& str) {
std::cout << str << std::endl;
return "I have returned";
}
int main(void) {
using test_print_type = std::string (*)(const std::string& str);
Invoker<test_print_type> get_value{ (std::intptr_t)test };
auto ret = get_value.invoke("Hello I am a testing function\n");
std::cout << ret << std::endl; // Errors here
std::system("PAUSE");
return 0;
}

If you want to return the value from the invoked function, I think you need to separate the return type into its own template parameter.
#include <cstdint>
#include <string>
#include <iostream>
#include <utility>
template <class ReturnType, class...Args>
class Invoker {
public:
Invoker(std::intptr_t address) :
address(address)
{ }
ReturnType invoke(Args&&... parameters) {
auto func = (ReturnType(*)(Args...)) address;
return func(std::forward<Args>(parameters)...);
}
private:
std::intptr_t address;
};
std::string test(const std::string& str) {
std::cout << str << std::endl;
return "I have returned";
}
int main(void) {
Invoker<std::string, const std::string&> get_value{ (std::intptr_t)test };
auto ret = get_value.invoke("Hello I am a testing function\n");
std::cout << ret << std::endl; // Errors here
return 0;
}

Related

How check instantiation of one type by another with templates?

In my case there is func:
// msg can be std::string, std::wstring, const char*, const wchar_t*, ...
template<typename StrType>
void Log(StrType msg) {
if std::string(msg) can be created from msg {
// do smth
}
if std::wstring(msg) can be created from msg {
// do smth
}
else {
// wrong argument
}
}
and i have to check if the std::string(wstring) can be created by 'msg' to do appropriate actions.
Since C++17, you may use a constexpr if to check whether std::string or std::wstring can be constructed from the argument you pass to Log:
template <typename StrType>
void Log(StrType msg) {
if constexpr (std::is_constructible_v<std::string, StrType>) {
// do smth
} else if (std::is_constructible_v<std::wstring, StrType>) {
// do smth
} else {
// wrong argument
}
}
You can either use SFINAE (tested for C++17) or Concepts (C++20)
#include <iostream>
#include <type_traits>
#include <string>
//---------------------------------------------------------------------------------------------------------------------
// C++17 approach
// Use SFINAE to only generate void return type if predicate is met.
template<typename StrType>
auto Log(const StrType& msg) -> std::enable_if_t<std::is_constructible_v<std::string, StrType>, void>
{
std::cout << "can construct std::string from msg : " << std::string{ msg } << "\n";
}
template<typename StrType>
auto Log(const StrType& msg) -> std::enable_if_t<std::is_constructible_v<std::wstring, StrType>, void>
{
std::wcout << L"can construct std::wstring from msg : " << std::wstring{ msg } << L"\n";
}
//--------------------------------------------------------------------------------------------------------------------
// C++20 approach (concepts)
template<typename StrType>
concept StdStringCompatible = std::is_constructible_v<std::string, StrType>;
template<typename StrType>
concept StdWStringCompatible = std::is_constructible_v<std::wstring, StrType>;
auto Log20(StdStringCompatible auto const& msg)
{
std::cout << "can construct std::string from msg : " << std::string{ msg } << "\n";
}
auto Log20(StdWStringCompatible auto const& msg)
{
std::wcout << L"can construct std::wstring from msg : " << std::wstring{ msg } << L"\n";
}
//--------------------------------------------------------------------------------------------------------------------
int main()
{
// to show you how you can check if a std::string or std::wstring can be constructed from a type
static_assert(std::is_constructible_v<std::string, const char*>);
static_assert(std::is_constructible_v<std::wstring, const wchar_t*>);
const char* msg = "const char* message";
const wchar_t* wmsg = L"const wchar_t* message";
Log(msg);
Log(wmsg);
// Log(10); // will not compile as intended
Log20(msg);
Log20(wmsg);
// Log20(10); // will not compile as intended
return 0;
}
If you're ok with a compiler error, if the string is neither convertible to std::string nor std::wstring, you could simply rely on CTAD (Class Template Argument Deduction) to determine the type parameters for std::basic_string for you.
(std::string and std::wstring both are aliases for std::basic_string specializations.)
void DoSomething(std::string const& str)
{
std::cout << "std::string\n";
}
void DoSomething(std::wstring const& str)
{
std::cout << "std::wstring\n";
}
template<typename StrType>
void Log(StrType&& msg) {
DoSomething(std::basic_string(std::forward<StrType>(msg)));
}
int main() {
using namespace std::literals::string_view_literals;
Log("Foo bar");
Log(L"Foo bar");
Log("abc"sv);
return 0;
}
This approach requires C++17 or later.

compiler error with C++ template says that is not the member of struct

I'm a newer of using C++ template and I got trouble with template compiling.
I want to write a similar factory method with template but compiler error says that 'ip is not the member of _FileWriterInfo'. I was confused because it has be defined in NetWriterInfo struct but not in FileWriterInfo. And if I cancel the 'ip' member defination, compiler works. Apparently T param of NetWriter may infer to FileWriterInfo struct by mistake. How can I get rid of it? plz help.
#include <iostream>
#include <string>
enum WriterFormat
{
WTYPE_FILE = 0,
WTYPE_NET = 1
};
typedef struct _FileWriterInfo
{
std::string name;
std::string page;
}FileWriterInfo;
typedef struct _NetWriterInfo
{
std::string name;
std::string ip;
}NetWriterInfo;
template<typename T>
class Writer
{
public:
virtual ~Writer() {}
virtual std::string Write(T info) = 0;
};
template<typename T>
class FileWriter : public Writer<T>
{
public:
std::string Write(T info) override {
std::cout << "name:" << info.name << "\n";
std::cout << "page:" << info.page << "\n";
return info.name;
}
};
template<typename T>
class NetWriter : public Writer<T>
{
public:
std::string Write(T info) override {
std::cout << "name:" << info.name << "\n";
std::cout << "ip:" << info.ip << "\n";
return info.name;
}
};
class Creator
{
Creator() {};
public:
template<typename T>
static Writer<T>* CreateWriter(WriterFormat fmt)
{
Writer<T>* p = nullptr;
if (fmt == WTYPE_FILE)
p = new FileWriter<T>;
if (fmt == WTYPE_NET)
p = new NetWriter<T>;
return p;
}
};
void WriteFile()
{
FileWriterInfo info = { "Hello","100" };
Writer<FileWriterInfo>* w = Creator::CreateWriter<FileWriterInfo>(WTYPE_FILE);
w->Write(info);
return;
}
int main()
{
WriteFile();
return 0;
}
The CreateWriter function instantiates the FileWriter and NetWriter classes with the FileWriterInfo structure. Accordingly, the compiler tries to instantiate the NetWriter::Write function with the type FileWriterInfo, and we get an error.
You can place Write methods directly to FileWriterInfo and NetWriterInfo stuctures (according to the principle of data encapsulation). It also can simplify the code.

using template arguments to specify policy

I got to know that we can also pass template arguments to choose which function should execute. I found them good alternative to function pointers since function pointers has run time cost but template parameters does not. Also, template parameters can be made inline whereas function pointers are not.
Alright then, this is what I wrote to depict my understanding on it. I came close but missing some minor detail somewhere.
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.length()) && (i < str2.length()); ++i) {
if (C::eq(str1[i], str2[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<String<std::string>, Cmp1<std::string> >(s, t);
// compare(s, t);
}
Details of the code:
I have an class String, which take an parameter and create member function of that type.
I have an compare function, which takes two String& arguments. Comparison function is passed to it.
Cmp1 and Cmp2 are two compare functions.
compare<String<std::string>, Cmp1<std::string> >(s, t);
does not get compile here. I tried some other ways to call but in vain.
Looks like you want something like that:
#include <iostream>
#include <string>
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.str.length()) && (i < str2.str.length()); ++i) {
if (C::eq(str1.str[i], str2.str[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
public:
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
public:
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<std::string, Cmp1<char> >(s, t);
// compare(s, t);
}
code
Explanations:
You already have String in definition of compare, you need to just send T which is std::string in your case.
You are trying to go through entire std::string, in compare, so, now your code compiles.
You calling cmp on str[index], that is actually char, so you need to call cmp with char template argument.

Getting class name as a string in static method in C++

Assume we are working with Clang strictly. No other compiler is being used. Also note that Clang supports CXX ABI.
We are using C++14.
Normally, we would get demangled class name like so:
#include <cxxabi.h>
class GoodClass {
public:
virtual const char *foo() const noexcept;
}
const char *
GoodClass::foo() const noexcept
{
// Naive implementation, not gonna' check any errors and stuff.
int32_t status = 0;
return abi::__cxa_demangle(typeid(*this).name(), 0, 0, &status);
}
This method will help us when we need class names of public subclasses of this class:
class SomeSubclassOfGoodClass : public GoodClass { }
SomeSubclassOfGoodClass object;
std::cout << object.foo(); // prints "SomeSubclassOfGoodClass"
However, in static methods, we could not use this since there is no instance. Therefore, it is impossible to serve an object to the typeid directive.
The examplary method serves well (with polymorphism), however it needs an instance to operate. This would involve problems about OO (such as constructors).
What would you do in a situation like this?
Thank you for your attention.
The use of demangle needs a little work. At the moment you have a memory leak.
Here's one way to solve that:
#include <cxxabi.h>
#include <memory>
#include <iostream>
#include <string>
#include <typeinfo>
#include <typeindex>
#include <cassert>
#include <stdexcept>
struct demangled_string
{
using ptr_type = std::unique_ptr<char, void(*)(void*)>;
demangled_string(ptr_type&& ptr) noexcept;
const char* c_str() const;
operator std::string() const;
std::ostream& write(std::ostream& os) const;
private:
ptr_type _ptr;
};
inline std::ostream& operator<<(std::ostream& os, const demangled_string& str)
{
return str.write(os);
}
inline std::string operator+ (std::string l, const demangled_string& r) {
return l + r.c_str();
}
inline std::string operator+(const demangled_string& l, const std::string& r)
{
return std::string(l) + r;
}
demangled_string demangle(const char* name);
demangled_string demangle(const std::type_info& type);
demangled_string demangle(std::type_index type);
template<class T>
demangled_string demangle(T* p) {
return demangle(typeid(*p));
}
template<class T>
demangled_string demangle()
{
return demangle(typeid(T));
}
// implementation
demangled_string::demangled_string(ptr_type&& ptr) noexcept
: _ptr(std::move(ptr))
{}
std::ostream& demangled_string::write(std::ostream& os) const
{
if (_ptr) {
return os << _ptr.get();
}
else {
return os << "{nullptr}";
}
}
const char* demangled_string::c_str() const
{
if (!_ptr)
{
throw std::logic_error("demangled_string - zombie object");
}
else {
return _ptr.get();
}
}
demangled_string::operator std::string() const {
return std::string(c_str());
}
demangled_string demangle(const char* name)
{
using namespace std::string_literals;
int status = -4;
demangled_string::ptr_type ptr {
abi::__cxa_demangle(name, nullptr, nullptr, &status),
std::free
};
if (status == 0) return { std::move(ptr) };
switch(status)
{
case -1: throw std::bad_alloc();
case -2: {
std::string msg = "invalid mangled name~";
msg += name;
auto p = (char*)std::malloc(msg.length() + 1);
strcpy(p, msg.c_str());
return demangled_string::ptr_type { p, std::free };
}
case -3:
assert(!"invalid argument sent to __cxa_demangle");
throw std::logic_error("invalid argument sent to __cxa_demangle");
default:
assert(!"PANIC! unexpected return value");
throw std::logic_error("PANIC! unexpected return value");
}
}
demangled_string demangle(const std::type_info& type)
{
return demangle(type.name());
}
demangled_string demangle(std::type_index type)
{
return demangle(type.name());
}
std::string method(const demangled_string& cls, const char* method)
{
return std::string(cls) + "::" + method;
}
// test
class test_class
{
using this_class = test_class;
static auto classname() { return demangle<this_class>(); }
public:
static void test1() {
std::cout << method(demangle<this_class>(), __func__) << std::endl;
std::cout << method(classname(), __func__) << std::endl;
}
void test2() {
std::cout << method(demangle(this), __func__) << std::endl;
std::cout << method(classname(), __func__) << std::endl;
}
};
int main()
{
test_class t;
t.test1();
t.test2();
}
expected output:
test_class::test1
test_class::test1
test_class::test2
test_class::test2
The typeid operator may also be applied to a type, not just an expression: typeid(GoodClass) ought to work when you cannot access this.
Edit: without an instance you need to turn to static polymorphism. You could have a mix in base class Identifiable<X> which has a static method with the code you suggested above, but using typeid(X) instead. Your classes need to extend this class passing themselves as the template parameter (the curiously recursive template pattern), but it is not possible to ensure that a class does so:
class C : public Identifiable<C> {}; // method returns C
class D : public Identifiable<C> {}; // also returns C

call functions depending on a string Parameter

I try to find a way to call functions depending on one String-Parameter.
Enums or Int are ok too for the Parametertype. Maybe there is something more ?
Is there a way to do it like this:
myFunction(string functionParameter, int value){
this->functionParameter(value);}
What is the best way for this? I know there are some similar Questions, but i didnt found a Answer that really fits my Problem.
Just use a map to map from strings to functions:
void f1()
{
std::cout << "f1!" << std::endl;
}
void f2()
{
std::cout << "f2!" << std::endl;
}
void f3()
{
std::cout << "f3!" << std::endl;
}
int main()
{
std::unordered_map<std::string,std::function<void()>> map;
map["f1"] = f1;
map["f2"] = f2;
map["f3"] = f3;
map["f1"]();
map["f2"]();
map["f3"]();
}
This outputs:
f1!
f2!
f3!
C++ doesn't have direct support to call functions using the name. You'll need to create the mapping somehow. The easiest approach is probably to create a map of a suitable std::function<...> type:
void f(int);
void g(int);
typedef std::function<void(int)> Function;
std:: map<std::string, Function> functions;
// ...
functions["f"] = f;
functions["g"] = g;
void call(std::string const& name, int x) {
auto it = functions.find(name);
if (it->second != functions.end()) {
it->second(x);
}
else {
// deal with unknown functions
}
}
You can map the string to the function pointer. Try something like this:
#include <iostream>
#include <string>
#include <functional>
#include <map>
class X;
template<class X>
class handler_factory;
template<>
class handler_factory<X>
{
private:
using HandlerType = void (X::*)(int);
public:
handler_factory();
HandlerType get(const std::string& name) const
{
if (handlers.find(name) == handlers.end())
return nullptr;
else
return (*handlers.find(name)).second;
}
private:
std::map<std::string, HandlerType> handlers;
};
class X
{
public:
friend class handler_factory<X>;
private:
void f(int);
void h(int);
};
handler_factory<X>::handler_factory()
{
handlers["f"] = &X::f;
handlers["h"] = &X::h;
}
void X::f(int) { std::cout << "X::f();"; }
void X::h(int) { std::cout << "X::h();"; }
Your class (in this example X) can have a function dispatch_method that looks like:
template<typename... Args>
void dispatch_method(const std::string& name, Args&&... args)
{
if (find_handler(name))
(this->*find_handler(name))(std::forward<Args>(args...));
}
Where find_handler is a helper method:
private:
auto find_handler(const std::string& name)
-> decltype(handler_factory<X>().get(name))
{
return handler_factory<X>().get(name);
}
Then you can call it like this:
int main()
{
X{}.dispatch_method("f", 5);
}
You may use something like:
#include <map>
#include <functional>
#include <stdexcept>
#include <string>
template<typename T> class Caller;
template<typename Ret, typename... Args>
class Caller<std::function<Ret(Args...)>>
{
public:
typedef std::function<Ret(Args...)> FuncType;
void add(const std::string& name, FuncType f)
{
functions[name] = f;
}
Ret call(const std::string& name, Args... args)
{
auto it = functions.find(name);
if (it == functions.end()) {
// Or any other error
throw std::runtime_error("unknown " + name + "function");
}
return (it->second)(args...);
}
private:
std::map<std::string, FuncType> functions;
};
So lets test it:
int minus(int a) { return -a; }
int main(int argc, char** argv)
{
Caller<std::function<int (int)>> caller;
caller.add("+1", [](int a) { return a + 1; } );
caller.add("minus", minus);
caller.call("minus", -42); // calls minus(-42), returns 42
caller.call("+1", 41); // calls the lambda, returns 42
return 0;
}
This is similar to question here. You need to create a map like this map<string, class::method>, then you can use its signature to search for function and call it.
Two ways are available for you:
1. Without using any 3rd-party library (in row C++):
#include <map>
#include <string>
struct Math
{
double sinFunc(double x) { return 0.33; };
double cosFunc(double x) { return 0.66; };
};
typedef double (Math::*math_method_t)(double);
typedef std::map<std::string, math_method_t> math_func_map_t;
int main()
{
math_func_map_t mapping;
mapping["sin"] = &Math::sinFunc;
mapping["cos"] = &Math::cosFunc;
std::string function = std::string("sin");
math_func_map_t::iterator x = mapping.find(function);
int result = 0;
if (x != mapping.end()) {
Math m;
result = (m.*(x->second))(20);
}
}
2. By using Boost library: The most convenient notation for method is function<signature> where function is either included in boost or in <utility>.
The signature would be like this.
map<string, function<double (double)> map; ...
map["sin"](1.0);