I want to export SRect and SRectVector from C++ to Lua, but compile fails.
What is the proper way to do it?
Compiler: vs2019, vc++11
OS: Win10 64
Push() meets compile error,
I think the argument is just SRectVector *, why the compiler thinks it is 'std::vector<SRect,std::allocator<_Ty>>'?
class SRect{
public:
int left;
int top;
int right;
int bottom;
SRect(int l, int t, int r, int b)
: left(l)
, top(t)
, right(r)
, bottom(b){}
//...
};
typedef std::vector<SRect> SRectVector;
luabridge::getGlobalNamespace(L)
.beginClass <SRect>("SRect")
.addConstructor <void(*) (int, int, int, int)>()
.addProperty("left", &SRect::left)
//...
.endClass()
.beginClass <SRectVector>("SRectVector")
.addFunction("Push",
std::function <void(SRectVector*, const SRect&)>(
[](SRectVector* vec, const SRect& rc) { (*vec).push_back(rc); }))
//...
.endClass()
.endNamespace();
```
1>E:\Code\include\LuaBridge/detail/TypeList.h(177): error C2664: 'luabridge::detail::TypeListValues<luabridge::detail::TypeList<Param,luabridge::detail::TypeList<const SRect&,luabridge::detail::MakeTypeList<>::Result>>>::TypeListValues(luabridge::detail::TypeListValues<luabridge::detail::TypeList<Param,luabridge::detail::TypeList<const SRect&,luabridge::detail::MakeTypeList<>::Result>>> &&)': cannot convert argument 1 from 'std::vector<SRect,std::allocator<_Ty>>' to 'Head'
1> with
1> [
1> Param=SRectVector *
1> ]
1> and
1> [
1> _Ty=SRect
1> ]
1> and
1> [
1> Head=SRectVector *
1> ]
1>E:\Code\include\LuaBridge/detail/TypeList.h(179): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>E:\Code\include\LuaBridge/detail/TypeList.h(176): note: while compiling class template member function 'luabridge::detail::ArgList<Params,1>::ArgList(lua_State *)'
After more digging, I found the reason. A completed user defined class can be easily exported. But a container pointer not. Compiles OK after I added such code,
namespace LuaBridge
{
template <>
struct Stack <SRectVector*>
{
static void push(lua_State* L, SRectVector* ptr)
{
SRectVector** pp = (SRectVector**)lua_newuserdata(L, sizeof(SRectVector*));
*pp = ptr;
}
static SRectVector* get(lua_State* L, int index)
{
return (SRectVector*)lua_touserdata(L, index);
}
};
}
Or add a more generic one,
template <class T>
struct Stack <std::vector<T>*>
{
typedef typename std::vector<T>* ContainerPointerType;
static void push(lua_State* L, ContainerPointerType ptr)
{
ContainerPointerType* pp = (ContainerPointerType*)lua_newuserdata(L, sizeof(ContainerPointerType));
*pp = ptr;
}
static ContainerPointerType get(lua_State* L, int index)
{
return (ContainerPointerType)lua_touserdata(L, index);
}
};
Do not include <LuaBridge/Vector.h>, then solve this issue.
Related
I tried one here. Code as following:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <new>
#include <climits>
namespace test {
template <class T>
inline T* _allocate(ptrdiff_t size, T*) {
std::cout << "_allocate called" << std::endl;
T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
if (NULL == tmp) {
std::cerr << "out of memory" << std::endl;
exit(0);
}
return tmp;
}
template <class T>
inline void _deallocate(T* p) {
::operator delete(p);
}
template <class T1, class T2>
inline void _construct(T1* p, const T2& value) {
::new (p) T1(value);
}
template <class T>
inline void _destroy(T* p) {
p->~T();
}
template <class T>
class Allocator {
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template <class U>
struct rebind {
typedef Allocator<U> other;
};
pointer allocate(size_type n, const void* hint = 0) { return _allocate((difference_type)n, (pointer)0); }
void deallocate(pointer p, size_type n) { return _deallocate(p); }
void construct(pointer p, const T& value) { _construct(p, value); }
void destroy(pointer p) { _destroy(p); }
pointer address(reference x) { return (pointer)&x; }
const_pointer address(const_reference x) { return (const_pointer)&x; }
size_type max_size() const { return size_type(UINT_MAX / sizeof(T)); }
};
} // namespace test
static std::map<void*, uint64_t, std::less<void*>, test::Allocator<std::pair<void* const, uint64_t>>> global_map;
int main()
{
std::vector<std::string> vec = {
"Hello", "from", "GCC", "!"
};
std::cout << "xxxx " << global_map.size() << std::endl;
}
But it leads to compiling fail on Visual Studio 2019 x86:
Build started...
1>------ Build started: Project: ConsoleApplication1, Configuration: Debug Win32 ------
1>ConsoleApplication1.cpp
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\xtree(1096,27): error C2440: 'static_cast': cannot convert from 'test::Allocator<U>' to 'test::Allocator<U>'
1> with
1> [
1> U=std::_Tree_node<std::pair<void *const ,uint64_t>,void *>
1> ]
1> and
1> [
1> U=std::_Container_proxy
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\xtree(1096,27): message : No constructor could take the source type, or constructor overload resolution was ambiguous
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\xtree(1092): message : while compiling class template member function 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::~_Tree(void) noexcept'
1> with
1> [
1> _Kty=void *,
1> _Ty=uint64_t,
1> _Pr=std::less<void *>,
1> _Alloc=test::Allocator<std::pair<void *const ,uint64_t>>
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\map(348): message : see reference to function template instantiation 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::~_Tree(void) noexcept' being compiled
1> with
1> [
1> _Kty=void *,
1> _Ty=uint64_t,
1> _Pr=std::less<void *>,
1> _Alloc=test::Allocator<std::pair<void *const ,uint64_t>>
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\map(75): message : see reference to class template instantiation 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>' being compiled
1> with
1> [
1> _Kty=void *,
1> _Ty=uint64_t,
1> _Pr=std::less<void *>,
1> _Alloc=test::Allocator<std::pair<void *const ,uint64_t>>
1> ]
How to fix it?
Edit:
Found another solution. But do not know why. Code as https://godbolt.org/z/jvscsMx7T
This problem appeard in Visual Studio Debug mode , but solved when switching to Release mode. If it still bothers you, you can report problems to Developer Community.
I learned a bit about variadic templates and searched over the Internet for some samples and now trying to write some tricky code to call member a method of a variadic class template with one of its fields. I can't understand why it doesn't work. Please, help.
Here is sample classes:
class BarBase
{
public:
BarBase() = default;
virtual void call() = 0;
};
template<typename O, typename M, typename... A>
class Bar
: public BarBase
{
public:
Bar(O* o, M m, A&&... a)
: BarBase()
, m_o(o), m_m(m), m_a(std::forward<A>(a)...)
{ }
void call() override final
{
callInnerWithArgsInside();
}
private:
void callInnerWithArgsInside()
{
(m_o->*m_m)(m_a); // Some errors happends here
}
O* m_o;
M m_m;
std::tuple<typename std::remove_reference<A>::type...> m_a;
};
template<typename O, typename M, typename... A>
BarBase* crateBar(O* o, M m, A&&... a)
{
return new Bar<O, M, A...>(o, m, std::forward<A>(a)...);
}
And call from main:
struct Foo
{
void foo(int ii, float ff, std::string ss)
{
std::cout << "called" << std::endl;
}
};
int main()
{
Foo f;
int i = 10;
float ff = 20.2f;
std::string s = "Hello";
BarBase* bar = crateBar(&f, &Foo::foo, i, ff, s);
bar->call();
}
Errors:
main.cpp
1>d:\drafts_tests\main.cpp(203): error C2198: 'void (__thiscall Foo::* )(int,float,std::string)' : too few arguments for call
1> d:\drafts_tests\main.cpp(202) : while compiling class template member function 'void Bar::callInnerWithArgsInside(void)'
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
1> d:\drafts_tests\main.cpp(197) : see reference to function template instantiation 'void Bar::callInnerWithArgsInside(void)' being compiled
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
1> d:\drafts_tests\main.cpp(214) : see reference to class template instantiation 'Bar' being compiled
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
1> d:\drafts_tests\main.cpp(225) : see reference to function template instantiation 'BarBase *crateBar(O *,M,int &,float &,std::string &)' being compiled
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
you are passing a tuple to the function, rather than the individual type arguments. The following will pass the required type args to the call:
template<std::size_t... I>
void callInnerWithArgsInside2(std::index_sequence<I...>)
{
(m_o->*m_m)(std::get<I>(m_a)...);
}
void callInnerWithArgsInside()
{
return callInnerWithArgsInside2( std::make_index_sequence<sizeof...(A)>());
}
live demo
EDIT1: C++11 version
I have implemented a C++11 version, see updated live demo
I'm trying to make a manager, which provides access via templates to containers that store different types of data.
First of all, i made base manager class for storing different type of data
template <typename T>
class BaseMapManager{
public:
T add(T element, std::string name);
T remove(T element);
T remove(std::string name);
T remove(unsigned int id);
T get(std::string name);
T get(unsigned int id);
BaseMapManager() { id = 0; };
~BaseMapManager() { nameMap.clear(); idMap.clear(); };
protected:
std::map<std::string, T> nameMap;
std::map<unsigned int, T> idMap;
//each element of type T gets new unique id
unsigned int id;
//hide it
BaseMapManager(const BaseMapManager&) {};
BaseMapManager& operator=(const BaseMapManager&) {};
};
Then i made my concrete manager, which had to store 3 types of baseMapManagers:
class ResourceManager{
public:
//creates singleton
static ResourceManager* init(){
static ResourceManager singleton;
return &singleton;
}
template <typename T>
void load_resource(std::string path, std::string name){
get_map<std::shared_ptr<T>>().add(std::shared_ptr<T>(new T(path, name), name);
}
template <typename T>
std::shared_ptr<T> get_resource(std::string name){
get_map<T>().get(name);
}
template <typename T>
std::shared_ptr<T> get_resource(unsigned int id){
get_map<T>().get(id);
}
private:
BaseMapManager<std::shared_ptr<AnimationResource> > animationMap;
BaseMapManager<std::shared_ptr<ImageResource> > imageMap;
BaseMapManager<std::shared_ptr<FontResource> > fontMap;
template <typename T>
BaseMapManager<T>& get_map(){
if (std::is_same<T, std::shared_ptr<AnimationResource> >() == true) return animationMap;
if (std::is_same<T, std::shared_ptr<ImageResource> >() == true) return imageMap;
if (std::is_same<T, std::shared_ptr<FontResource> >() == true) return fontMap;
};
};
and now i got this:
1>------ Build started: Project: BOSS, Configuration: Debug Win32 ------
1> main.cpp
1>d:\programming\github projects\boss\boss\new\resourcemanager\resourcemanager.h(43):
error C2440: 'return' : cannot convert from 'BaseMapManager<T>' to 'BaseMapManager<T> &'
1> with
1> [
1> T=std::shared_ptr<ImageResource>
1> ]
1> and
1> [
1> T=std::shared_ptr<AnimationResource>
1> ]
1> d:\programming\github projects\boss\boss\new\resourcemanager\resourcemanager.h(21) : see reference to function template instantiation 'BaseMapManager<T> &ResourceManager::get_map<std::shared_ptr<_Ty>>(void)' being compiled
1> with
1> [
1> T=std::shared_ptr<AnimationResource>,
1> _Ty=AnimationResource
1> ]
1> d:\programming\github projects\boss\boss\new\main.cpp(17) : see reference to function template instantiation 'void ResourceManager::load_resource<AnimationResource>(std::string,std::string)' being compiled
1>d:\programming\github projects\boss\boss\new\resourcemanager\resourcemanager.h(44): error C2440: 'return' : cannot convert from 'BaseMapManager<T>' to 'BaseMapManager<T> &'
1> with
1> [
1> T=std::shared_ptr<FontResource>
1> ]
1> and
1> [
1> T=std::shared_ptr<AnimationResource>
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The goal is - providing access to different types on data using template functions like
manager->get_resource<AnimationResource>(itsName) //get it or
manager->load_resource<FontResource>(itsPath, itsName) //add it
Is there a better way to handle this maybe? Thanks!
edit
The source of your problem seams to be the is_same function not resolving correctly at compile time.
/edit
You can always have template functions that only work with the specified types.
For example:
template<>
BaseMapManager<AnimationResource> get_map<AnimationResource>()
{
return animationMap;
}
template<>
BaseMapManager<ImageResource> get_map<ImageResource>()
{
return imageMap;
}
template<>
BaseMapManager<FontResource> get_map<FontResource>()
{
return fontMap;
}
I'm using Boost.PropertyTree for a project and I want to use user-defined types for Key and Data instead of the std::string that Boost uses in the ptree typedef.
However when I typedef basic_ptree myself I get the following compiler errors:
1> main.cpp
1>c:\boost_1_49_0\boost\property_tree\ptree.hpp(82): error C2027: use of undefined type 'boost::property_tree::path_of<Key>'
1> with
1> [
1> Key=int
1> ]
1> c:\users\mathias\documents\visual studio 2012\projects\testappern\testappern\main.cpp(10) : see reference to class template instantiation 'boost::property_tree::basic_ptree<Key,Data>' being compiled
1> with
1> [
1> Key=int,
1> Data=int
1> ]
1>c:\users\mathias\documents\visual studio 2012\projects\testappern\testappern\main.cpp(13): error C2664: 'boost::property_tree::basic_ptree<Key,Data>::add_child' : cannot convert parameter 1 from 'int' to 'const boost::type &'
1> with
1> [
1> Key=int,
1> Data=int
1> ]
1> Reason: cannot convert from 'int' to 'const boost::type'
1> The target type has no constructors
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The following snippet shows and example how I typedef basic_tree and get the compiler errors:
#include <iostream>
#include <boost\property_tree\ptree.hpp>
using namespace boost::property_tree;
typedef basic_ptree<int, int> IntTree;
int main(int argc, char* argv[])
{
IntTree tree;
IntTree child;
int index = 42;
tree.add_child(index, child);
return 0;
}
So my question is, how do I typedef it correctly?
If it's any interest I'm running MSVC 2012.
Thanks in advance!
According to the contents of boost/property_tree/ptree_fwd.hpp, if you want to use a custom type as a key, you should follow this:
/// If you want to use a custom key type, specialize this struct for it
/// and give it a 'type' typedef that specifies your path type. The path
/// type must conform to the Path concept described in the documentation.
/// This is already specialized for std::basic_string.
So you can not simply use int. Refer to the documentation for more information, as the code says.
Here is an example of basic_ptree <int, int>
//path class must conform Path concept
template<> class boost::property_tree::path_of < int >
{
public:
typedef int key_type;
typedef boost::property_tree::path_of < int > type;
boost::property_tree::path_of<int>(vector<int>& vals)
{
std::transform(vals.begin(), vals.end(), back_inserter(_impl),
[&](int v) -> int{ return v; });
}
key_type reduce()
{
key_type res = *_impl.begin();
_impl.pop_front();
return res;
}
bool empty() const
{
return _impl.empty();
}
bool single() const
{
return _impl.size() == 1;
}
std::string dump() const
{
std::string res;
std::for_each(_impl.begin(),
_impl.end(), [&res](key_type k) -> void
{
res.append(".");
res.append(boost::lexical_cast<std::string>(k));
});
return res;
}
private:
deque<key_type> _impl;
};
//usage:
typedef boost::property_tree::basic_ptree < int, int> custom_int_tree_t
//or
typedef boost::property_tree::basic_ptree < int, void*> custom_int_tree2_t
Wordy title, yes, but I was unsure how else to say it. Suppose I have a container class which has two template parameters, the first of which is a type, the second of which is the size of the local storage for the container.
Now we have multiple containers with a different container storage size. Essentially, the container functions (all the public ones, anyway) only really care about T; N is only used to allocate local storage (an allocator is used if N is not enough).
I have put together a simple example implementation that showcases the problem I am having.
#include <iostream>
template <typename T, size_t N = 10>
class TestArray
{
public:
T Local[N];
class Iterator
{
public:
T* Array;
int Index;
Iterator() : Array(NULL), Index(-1) { }
Iterator(T* _array, int _index) : Array(_array), Index(_index) { }
bool operator == (const Iterator& _other) const
{
return _other.Index == Index && _other.Array == Array;
}
void Next() { ++Index; }
void Prev() { --Index; }
T& Get() { return Array[Index]; }
};
T& operator [] (const int _index) { return Local[_index]; }
Iterator Begin() { return Iterator(Local, 0); }
Iterator End() { return Iterator(Local, N); }
template <size_t _N>
void Copy(const TestArray<T, _N> &_other, int _index, int _count)
{
int i;
for (i = 0; i < _count; i++)
Local[_index + i] = _other[i];
}
};
This is really a two part question. I will concern this question only with the first part, and ask another regarding the second. I tried using it as follows:
int main() {
TestArray<int> testArray1;
TestArray<int, 25> testArray2;
TestArray<int>::Iterator itr1;
TestArray<int, 25>::Iterator itr2;
itr1 = testArray1.Begin();
for (itr1 = testArray1.Begin(); itr1 != testArray1.End(); itr1.Next())
{
itr1.Get() = itr1.Index;
}
testArray2.Copy(testArray1, 0, 10);
for (itr2 = testArray2.Begin(); itr2 != testArray2.End(); itr2.Next())
{
std::cout << itr2.Get() << std::endl;
}
return 0;
}
Here is an IDEONE link: http://ideone.com/1XKwD
When compiled with gcc-4.3.4, I get the following.
prog.cpp: In member function ‘void TestArray<T, N>::Copy(const TestArray<T, _N>&, int, int) [with unsigned int _N = 10u, T = int, unsigned int N = 25u]’:
prog.cpp:82: instantiated from here
prog.cpp:63: error: passing ‘const TestArray<int, 10u>’ as ‘this’ argument of ‘T& TestArray<T, N>::operator[](int) [with T = int, unsigned int N = 10u]’ discards qualifiers
When compiled with VS2010, I get the following.
1>------ Build started: Project: testunholytemplatemess, Configuration: Debug Win32 ------
1> main.cpp
1>c:\users\james\documents\testproj\testunholytemplatemess\testunholytemplatemess\main.cpp(63): error C2678: binary '[' : no operator found which takes a left-hand operand of type 'const TestArray<T>' (or there is no acceptable conversion)
1> with
1> [
1> T=int
1> ]
1> c:\users\james\documents\testproj\testunholytemplatemess\testunholytemplatemess\main.cpp(44): could be 'int &TestArray<T>::operator [](const int)'
1> with
1> [
1> T=int
1> ]
1> while trying to match the argument list '(const TestArray<T>, int)'
1> with
1> [
1> T=int
1> ]
1> c:\users\james\documents\testproj\testunholytemplatemess\testunholytemplatemess\main.cpp(82) : see reference to function template instantiation 'void TestArray<T,N>::Copy<10>(const TestArray<T> &,int,int)' being compiled
1> with
1> [
1> T=int,
1> N=25
1> ]
Maybe I'm being thick, but I'm failing to interpret what either of these is actually trying to tell me (still somewhat new to templates). I also fail to understand why the operator [] method should really care about N, or the fact that I'm calling operator [] on a container with a different N value. If you change _other[i] to _other.Local[i], it works fine.
Does anyone have any suggestions?
You have to overload two versions for the []-operator, a const one and a non-const one:
T & operator [] (size_t _index) { return Local[_index]; }
const T & operator [] (size_t _index) const { return Local[_index]; }
Your constant Copy function is only allowed to use the second, constant version!