I want to wrap a class derived from std::vector with some extend functions into csharp with swig. the functions from vector are also needed like push_back to add new item into the class (which named Add in csharp).
I tried with default setting with swig, IntArray is valid in csharp .But, vector's functions are invalid.
if i try to define a vector in the .i file:
namespace std{
%template(ScalarVec) vector<ScalarTest>;
}
a class named ScalarVec have functions like vector is valid in csharp, but without the extend function.
How to wrap the ScalarArray to csharp with swig?
The following is a simple example.
#include <vector>
#include <numeric>
namespace test
{
struct ScalarTest {
int val;
};
struct ScalarArray : public std::vector<ScalarTest>
{
int sum() const {
int res = 0;
for (const ScalarTest &item : *this) {
res += item.val;
}
return res;
}
};
}
SWIG is picky about order of declarations. Below correctly wraps your example code and can call the sum function. I'm not set up for C# so the demo is created for Python:
test.i
%module test
%{
// Code to wrap
#include <vector>
#include <numeric>
namespace test
{
struct ScalarTest {
int val;
};
struct ScalarArray : public std::vector<ScalarTest>
{
int sum() const {
int res = 0;
for (const ScalarTest &item : *this) {
res += item.val;
}
return res;
}
};
}
%}
namespace test
{
struct ScalarTest {
int val;
};
}
%include <std_vector.i>
// Must declare ScalarTest above before instantiating template here
%template(ScalarVec) std::vector<test::ScalarTest>;
// Now declare the interface for SWIG to wrap
namespace test
{
struct ScalarArray : public std::vector<ScalarTest>
{
int sum() const;
};
}
demo.py
import test
x = test.ScalarArray()
a = test.ScalarTest()
a.val = 1
b = test.ScalarTest()
b.val = 2
x.push_back(a)
x.push_back(b)
print('sum',x.sum())
print(x[0].val,x[1].val)
Output:
sum 3
1 2
Related
I want to store 6 pointers to objects. But the Pointers can be in any order and point to different instances of (12) subclasses of one superclass, so they are possibly all of different types.
Arrays and such don't work, because the superclass is virtual.
Vectors and Tuples don't work, because the datatypes are of no specific order and are not known at compile time.
Im fairly new to C++ and I'm running out of Ideas.
Here some code to elaborate the problem:
baseclass{
getfoobar()=0;
}
subclass1{
getfoobar(){...}
}
subclass2{
getfoobar(){...}
}
---
#include <otherclasses.h>
memoryclass{
baseclass mem[6];
}
is basically what im trying.
You CAN create a vector of superclass pointers. It will achieve what you want, as it will call the overwritten function. This is of course assuming you are talking about inheritance, like:
#include <vector>
using type = ????;
class A {
virtual type foo() = 0;
}
class B : A {
type foo() override { ... }
}
class C : A {
type foo() override { ... }
}
int main(){
std::vector<A*> arr;
arr.push_back(new B);
arr.push_back(new C);
}
Now if I misunderstood and this doesn't work for some reason (i.e. they just share the function and are not actually related classes), you can do something like this, but it is not very nice:
#include <concepts>
#include <vector>
#include <functional>
using type = ?????;
template <class T> requires requires(T t){
{ t.foo() } -> std::same_as<type>;
}
std::function<type()> getFunction(T* t){
return [t](){ return t->foo(); };
}
int main(){
std::vector<std::function<type()>> arr;
arr.push_back(getFunction(new B));
arr.push_back(getFunction(new C));
}
I don't recommend this over the first option unless you have very good reason to do this.
Note: Since you didn't specify return type I winged it with ?????
Also: In the second you can replace template<class T> requires ... std::function<type()>, with just template<class T> std::function<type()>, if the compiler doesn't like #include <concepts>
You can try std::set<Superclass*>. Use pointers to your base superclass instead pointers to particular subclasses.
Actually I used std::shared_ptr<> smart pointer template to avoid raw memory management.
Example code:
#include <cstdlib>
#include <string>
#include <sstream>
#include <set>
#include <memory>
#include <iostream>
class baseclass {
public:
virtual std::string getfoobar() = 0;
};
typedef std::shared_ptr<baseclass> baseclass_ptr;
class subclass1 : public baseclass{
public:
std::string getfoobar() override {
return "from subclass1";
}
};
class subclass2 : public baseclass{
public:
std::string getfoobar() override {
return "from subclass2";
}
};
int main(int argc, char** argv) {
// Use current time as seed for random generator
std::srand(static_cast<unsigned>(std::time(nullptr)));
std::set<baseclass_ptr> container;
// Randomly generate number of elements
const int random_count = std::rand() % 10 + 1;
for (int i = 0; i < random_count; ++i) {
// Randomly create subclass1 or subclass2
if (std::rand() % 2) {
container.insert(std::make_shared<subclass1>());
}
else {
container.insert(std::make_shared<subclass2>());
}
}
// Iterate resulting container
std::cout << "size = " << container.size() << std::endl;
for (auto iterator : container) {
std::cout << "getfoobar(): " << iterator->getfoobar() << std::endl;
}
return 0;
}
I am currently trying to generate JSON with ordered keys and therefore used a workaround method. However, if I try to use it within my base and derived classes, I get an error which I do not really understand. It seems like it fails to call the to_Json methods (because the error appears if I try to map a DerivedClass-instance (test and test2) to my_json.
I have already tried the example without ordered keys (just by using json = nlohmann::json;) and it works completely fine. The keys in the output are sorted alphabetically and looks like this:
{
"cbor": "cbortest",
"diagnostic": "diagnose: corona",
"header": {
"headerId": 3,
"timestamp": "2019-12-10T16:04:00.00Z",
"version": "4.0.0"
},
"hex": "00f2",
"roundtrip": true
}
What I am trying to achieve through using the nlohmann fifo_map is to keep the insertion order and the final output therefore should look like this:
{
"header": {
"headerId": 3,
"timestamp": "2019-12-10T16:04:00.00Z",
"version": "4.0.0"
},
"cbor": "cbortest",
"hex": "00f2",
"roundtrip": true,
"diagnostic": "diagnose: corona"
}
Executing the following code outputs two errors:
Error C2440: 'initializing': cannot convert from 'BaseNamespace::SubNamespace::DerivedClass' to 'nlohmann::basic_json<my_workaround_fifo_map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>' ; in file: main.cpp
Please have a look at the following code:
In BaseClass.h:
#ifndef BASECLASS_H
#define BASECLASS_H
#include <stdint.h>
#include <string>
#include "nlohmann/json.hpp"
#include "fifo_map.hpp"
namespace BaseNamespace{
namespace SubNamespace{
class BaseClass {
public:
BaseClass () {};
virtual ~BaseClass () {};
uint32_t getHeaderId() const { return headerId; };
std::string getTimestamp() const { return timestamp; };
std::string getVersion() const { return version; };
void setHeaderId(uint32_t str) { headerId = str; };
void setTimestamp(std::string str) { timestamp = str; };
void setVersion(std::string bo) { version = bo; };
void setHeader(UAgvHeader const& header) {
setHeaderId(header.getHeaderId());
setTimestamp(header.getTimestamp());
setVersion(header.getVersion());
}
private:
uint32_t headerId;
std::string timestamp;
std::string version;
};
// A workaround to give to use fifo_map as map, we are just ignoring the 'less' compare
using namespace nlohmann;
template<class K, class V, class dummy_compare, class A>
using my_workaround_fifo_map = fifo_map<K, V, fifo_map_compare<K>, A>;
using my_json = basic_json<my_workaround_fifo_map>;
void to_json(my_json &j, const BaseClass &p)
{
j = my_json{
{ "headerId", p.getHeaderId() },
{ "timestamp", p.getTimestamp() },
{ "version", p.getVersion() }
};
}
void from_json(const my_json &j, BaseClass &p)
{
p.setHeaderId(j.at("headerId").get< std::uint32_t>());
p.setTimestamp(j.at("timestamp").get< std::string >());
p.setVersion(j.at("version").get<std::string>());
}
} // namespace SubNamespace
} // namespace BaseNamespace
#endif // BASECLASS_H_
In DerivedClass.h:
#ifndef DERIVEDCLASS_H
#define DERIVEDCLASS_H
#include <stdint.h>
#include <string>
#include "nlohmann/json.hpp"
#include <optional>
#include "BaseClass.h"
namespace BaseNamespace{
namespace SubNamespace{
class DerivedClass : public BaseClass {
public:
std::string getCBor() const { return cbor; };
std::string getHex() const { return hex; };
bool getRoundtrip() const { return roundtrip; };
std::optional<std::string> getDiagnostic() const { return diagnostic; };
void setCBor(std::string str) { cbor = str; };
void setHex(std::string str) { hex = str; };
void setRoundtrip(bool bo) { roundtrip = bo; };
void setDiagnostic(std::optional<std::string> opt_str) { diagnostic = opt_str; };
private:
std::string cbor;
std::string hex;
bool roundtrip;
std::optional<std::string> diagnostic = std::nullopt;
};
// A workaround to give to use fifo_map as map, we are just ignoring the 'less' compare
using namespace nlohmann;
template<class K, class V, class dummy_compare, class A>
using my_workaround_fifo_map = fifo_map<K, V, fifo_map_compare<K>, A>;
using my_json = basic_json<my_workaround_fifo_map>;
void to_json(my_json &j, const DerivedClass& p)
{
j["header"] = static_cast<BaseClass>(p);
j["cbor"] = p.getCBor();
j["hex"] = p.getHex();
j["roundtrip"] = p.getRoundtrip();
// assuming you only want a "diagnostic" key if there is an actual value;
// if not, store a nullptr and adjust the from_json accordingly
if (p.getDiagnostic() != std::nullopt)
{
j["diagnostic"] = p.getDiagnostic().value();
}
}
void from_json(const my_json &j, DerivedClass&p)
{
p.setHeader(j.at("header").get<BaseClass>());
p.setCBor(j.at("cbor").get< std::string >());
p.setHex(j.at("hex").get< std::string >());
p.setRoundtrip(j.at("roundtrip").get< bool >());
// if we also allow "null" values, then we need to add an "is_string()"
// check
if (j.count("diagnostic") != 0)
{
p.setDiagnostic(j.at("diagnostic").get< std::string >());
}
}
} // namespace SubNamespace
} // namespace BaseNamespace
#endif // DERIVEDCLASS_H
In main.cpp:
#include <iostream>
#include <string>
#include <nlohmann/json.hpp>
#include <iomanip>
#include <optional>
#include "DerivedClass.h"
using namespace nlohmann;
// A workaround to give to use fifo_map as map, we are just ignoring the 'less' compare
template<class K, class V, class dummy_compare, class A>
using my_workaround_fifo_map = fifo_map<K, V, fifo_map_compare<K>, A>;
using my_json = basic_json<my_workaround_fifo_map>;
int main(int argc, char* argv[]) {
BaseNamespace::SubNamespace::DerivedClass test;
test.setHeaderId(3);
test.setTimestamp("2019-12-10T16:04:00.00Z");
test.setVersion("4.0.0");
test.setCBor("cbortest");
test.setHex("00f2");
test.setRoundtrip(true);
test.setDiagnostic("diagnose: corona");
my_json j = test; // ERROR: no suitable conversion
std::cout << std::setw(2) << j << std::endl;
std::string str = R"({"header":
{ "headerId" : 4711,
"timestamp" : "1 Uhr",
"version" : "5.0.0"
},
"cbor" : "+X4A",
"hex" : "f97e00",
"roundtrip" : true,
"diagnostic" : "NaN"
})";
my_json j2 = my_json::parse(str);
BaseNamespace::SubNamespace::DerivedClass test2 = j2;
my_json k = test2; // ERROR: no suitable conversion
std::cout << std::setw(2) << k << std::endl;
return 0;
}
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.
I have the following config to evaluate and am using a factory to get an object to a subclass of MathOperation based on type.
class MathOperation {
Operation GetOperationType();
int Evaluate (config c);
}
config {
type = min
config {
type = average
int x
int y
}
config {
type = sum
int p
int q
}
...
}
For instance if x = 10, y = 20, p = 10, q = 2
the answer is min(average(10, 20), sum(10, 2)) = 12.
I am running into a circular dependency issue because each subclass of MathOperation needs to include the factory to evaluate it's subconfig and the factory ofcoruse needs to include each subclass of MathOperation. How do I resolve this?
This is what I currently have:
MathOperationFactory.h and cc
#include "average.h"
#include "min.h"
#include "sum.h"
std::unique_ptr<MathOperationObject> MakeObject(OperationType type) {
switch(type) {
case min : return MinOperation();
...
}
}
MinOperation.h and cc
#include "mathoperationfactory.h"
int Evaluate(Config c) {
int minimum = 1000; // large number.
ASSERT(config.type = min);
for(config : c) // repeated configs {
type t = c.type;
factory.MakeObject(t);
if(t.Evaluate < minimum) {
minimum = t;
}
}
return minimum;
}
The Factory doesn't need to know the subtype, it just needs to be able to new one up. One way to do this is with a Creator class whose job is to delegate the creation of the concrete object back to the class itself.
I'm using std::string here for names, but you could easily use int or Operation enum.
Something like:
#pragma once
#include <string> //
#include <map>
#include <typeinfo>
class MathOperation;
/************************************************************************/
/* MathOperation Factory */
/************************************************************************/
// Abstract Interface Type For Creator
struct CMathOperationCreator
{
virtual MathOperation* Create() = 0;
virtual ~CMathOperationCreator() {}
};
// Creator Map
std::map<std::string, CMathOperationCreator*, StringLessNoCaseCHAR>& GetMathOperationFactoryMap();
// Templated concrete creator, to be registered in the header of the concrete mathop type
template<class Derived>
struct CMathOperationConcreteCreator: public CMathOperationCreator
{
CMathOperationConcreteCreator(const std::string& theMathOperationTypeId)
{
auto aFactoryItem = GetMathOperationFactoryMap().find(theMathOperationTypeId);
if(aFactoryItem != GetMathOperationFactoryMap().end())
{
if(typeid(*aFactoryItem->second) == typeid(*this)) // avoid duplicates
return;
}
GetMathOperationFactoryMap()[theMathOperationTypeId] = this;
}
virtual MathOperation* Create() {return new Derived();}
};
//Factory Method
MathOperation* CreateMathOperation(const std::string& theMathOperationTypeId);
/**
* Macro to automatically register a MathOperation Type
*/
#define REGISTER_MathOperation( ConcreteMathOperation, name ) \
static CMathOperationConcreteCreator<ConcreteMathOperation> ConcreteMathOperation##Creator(name);
The CPP file:
// This is dumb, you don't have to do this, you just need a singleton factory that holds this map
std::map<std::string, CMathOperationCreator*, StringLessNoCaseCHAR>& GetMathOperationFactoryMap()
{
static std::map<std::string, CMathOperationCreator*, StringLessNoCaseCHAR> theMap;
return theMap;
}
MathOperation* CreateMathOperation( const std::string& theMathOperationTypeId )
{
auto aFactoryItem = GetMathOperationFactoryMap().find(theMathOperationTypeId);
if (aFactoryItem != GetMathOperationFactoryMap().end())
{
MathOperation* aObject = aFactoryItem->second->Create();
return aObject;
}
return NULL;
}
Register a class:
class MinOperation : public MathOperation {
Operation GetOperationType();
int Evaluate (config c);
};
REGISTER_MathOperation(MinOperation, "min");
Then, when you're parsing your tokens, you can query the factory for the operation:
MathOperation* pOp = CreateMathOperation(token.lowercase());
As pointed out in the comments, it's hard to be sure without seeing real code. However, most likely the issue is you are putting too many includes in the header files. if you just add #include "mathoperationfactory.h" in the cc file, you should be fine.
Also, you need to use include guards.
#pragma once makes sure that a header is only included once. Always put this as your first line in headers.
I am trying to create a generic function map using templates.The idea is to inherit from this generic templated class with a specific function pointer type. I can register a function in the global workspace, but I'd rather collect all the functions together in the derived class and register these in the constructor. I think I am almost here but I get a compile error. Here is a stripped down version of my code:
#include <iostream>
#include <string>
#include <map>
#include <cassert>
using namespace std;
int f(int x) { return 2 * x; }
int g(int x) { return -3 * x; }
typedef int (*F)(int);
// function factory
template <typename T>
class FunctionMap {
public:
void registerFunction(string name, T fp) {
FunMap[name] = fp;
}
T getFunction(string name) {
assert(FunMap.find(name) != FunMap.end());
return FunMap[name];
}
private:
map<string, T> FunMap;
};
// specific to integer functions
class IntFunctionMap : public FunctionMap<F> {
public:
int f2(int x) { return 2 * x; }
int g2(int x) { return -3 * x; }
IntFunctionMap() {
registerFunction("f", f); // This works
registerFunction("f2", f2); // This does not
}
};
int main()
{
FunctionMap<F> fmap; // using the base template class directly works
fmap.registerFunction("f", f);
F fun = fmap.getFunction("f");
cout << fun(10) << endl;
return 0;
}
The error I get is:
templatefunctions.cpp: In constructor ‘IntFunctionMap::IntFunctionMap()’:
templatefunctions.cpp:33: error: no matching function for call to ‘IntFunctionMap::registerFunction(const char [3], <unresolved overloaded function type>)’
templatefunctions.cpp:15: note: candidates are: void FunctionMap<T>::registerFunction(std::string, T) [with T = int (*)(int)]
Juan's answer is correct: member functions have an implicit first parameter, which is a pointer to the type of which they are a member. The reason your code fails to compile is that your map supports function pointers with type int (*)(int), but the type of f2 is int (IntFunctionMap::*)(int).
In the specific case that you show here, you can use std::function, which implements types erasure, to present free functions and member functions as the same type. Then you could do what you are trying to do. Note: this requires C++11.
#include <iostream>
#include <string>
#include <map>
#include <cassert>
#include <function>
#include <bind>
using namespace std;
int f(int x) { return 2 * x; }
int g(int x) { return -3 * x; }
typedef std::function<int (int)> F;
// function factory
template <typename T>
class FunctionMap {
public:
void registerFunction(string name, T fp) {
FunMap[name] = fp;
}
T getFunction(string name) {
assert(FunMap.find(name) != FunMap.end());
return FunMap[name];
}
private:
map<string, T> FunMap;
};
// specific to integer functions
class IntFunctionMap : public FunctionMap<F> {
public:
int f2(int x) { return 2 * x; }
int g2(int x) { return -3 * x; }
IntFunctionMap() {
registerFunction("f", f); // This works
registerFunction("f2", std::bind(&f2, this, _1)); // This should work, too!
}
};
int main()
{
FunctionMap<F> fmap; // using the base template class directly works
fmap.registerFunction("f", f);
F fun = fmap.getFunction("f");
cout << fun(10) << endl;
return 0;
}