Rapptz / sol

A C++11 Lua wrapper

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Registering a Inherited method

brunocanella opened this issue · comments

As of now, I couldn't figure out a better way to access a Derived's class method without overriding the Base's method. Example:

class Base {
public:
Base( int a_num ) : m_num(a_num) {}
int get_num() {
return m_num;
}
protected:
int m_num;
};

class Derived : public Base {
public:
Derived( int a_num ) : Base(a_num) {}
int get_num_10() {
return 10 * m_num;
}
int get_num() {
return Base::get_num();
}
};

//-------------------------------------------------------------//

sol::constructors<sol::types<int>> l_ctor_base;
sol::userdata<Base> l_userdata_base( "Base", l_ctor_base, "get_num", &Base::get_num );

l_lua.set_userdata( l_userdata_base );

l_lua.script( "base = Base.new( 5 )" );
l_lua.script( "print( base:get_num() )" );

sol::constructors<sol::types<int>> l_ctor_derived;
sol::userdata<Derived> l_userdata_derived( "Derived", l_ctor_derived, "get_num", &Derived::get_num, "get_num_10", &Derived::get_num_10 );

l_lua.set_userdata( l_userdata_derived );

l_lua.script( "derived = Derived.new( 7 )" );
l_lua.script( "print( derived:get_num_10() )" );
l_lua.script( "print( derived:get_num() )" );

//------------------------------------------//

If I don't override get_num in Derived, I get the following error when registering get_num:

no matching function for call to ‘sol::userdata::build_function_tables(const char [8], int (Base::)(), const char [11], int (Derived::)())’

It would be interesting to support inheritance, but if not, at least to come up with an workaround to this, since overriding all of the methods is usually not desired.

Other than that, great project! Keep up the good work :D

I just tried this bug for myself with the compiler VC++: there is no compiler or runtime error generated when I compile or run the code respectively. The full code I'm using is below. Again, there's no error: what compiler AND version are you using?

class Base {
public:
    Base( int a_num ) : m_num( a_num ) { }

    int get_num( ) {
        return m_num;
    }

protected:
    int m_num;
};

class Derived : public Base {
public:
    Derived( int a_num ) : Base( a_num ) { }

    int get_num_10( ) {
        return 10 * m_num;
    }
};

int main( ) {
    sol::state l_lua;
    l_lua.open_libraries( sol::lib::debug, sol::lib::base, sol::lib::io );
    sol::constructors<sol::types<int>> l_ctor_base;
    sol::userdata<Base> l_userdata_base( "Base", l_ctor_base, "get_num", &Base::get_num );

    l_lua.set_userdata( l_userdata_base );

    l_lua.script( "base = Base.new( 5 )" );
    l_lua.script( "print( base:get_num() )" );

    sol::constructors<sol::types<int>> l_ctor_derived;
    sol::userdata<Derived> l_userdata_derived( "Derived", l_ctor_derived, "get_num", &Derived::get_num, "get_num_10", &Derived::get_num_10 );

    l_lua.set_userdata( l_userdata_derived );

    l_lua.script( "derived = Derived.new( 7 )" );
    l_lua.script( "print( derived:get_num_10() )" );
    l_lua.script( "print( derived:get_num() )" );
}

I am using a Linux Mint 15 distro, with GNU Compiler 4.8:

g++ (Ubuntu 4.8.1-2ubuntu1~13.04) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

This is the command line that I am using, with the equivalent output:

g++ -I/usr/include/lua5.2 -I./ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -fPIC -c -o my_test.o my_test.cpp 
In file included from sol/table.hpp:28:0,
                 from sol/state.hpp:26,
                 from sol.hpp:25,
                 from my_test.cpp:9:
sol/userdata.hpp: In instantiation of ‘sol::userdata<T>::userdata(std::string, sol::constructors<CArgs ...>, Args&& ...) [with Args = {const char (&)[8], int (Base::*)(), const char (&)[11], int (Derived::*)()}; CArgs = {sol::types<int>}; T = Derived; std::string = std::basic_string<char>]’:
sol/userdata.hpp:146:78:   required from ‘sol::userdata<T>::userdata(const char*, sol::constructors<CArgs ...>, Args&& ...) [with Args = {const char (&)[8], int (Base::*)(), const char (&)[11], int (Derived::*)()}; CArgs = {sol::types<int>}; T = Derived]’
my_test.cpp:47:137:   required from here
sol/userdata.hpp:134:30: error: no matching function for call to ‘sol::userdata<Derived>::build_function_tables(const char [8], int (Base::*)(), const char [11], int (Derived::*)())’
         build_function_tables<0>(std::forward<Args>(args)...);
                              ^
sol/userdata.hpp:134:30: note: candidates are:
sol/userdata.hpp:111:10: note: template<long unsigned int N> void sol::userdata<T>::build_function_tables() [with long unsigned int N = N; T = Derived]
     void build_function_tables() {}
          ^
sol/userdata.hpp:111:10: note:   template argument deduction/substitution failed:
sol/userdata.hpp:134:30: note:   candidate expects 0 arguments, 4 provided
         build_function_tables<0>(std::forward<Args>(args)...);
                              ^
sol/userdata.hpp:114:10: note: template<long unsigned int N, class ... Args, class Ret> void sol::userdata<T>::build_function_tables(std::string, Ret T::*, Args&& ...) [with long unsigned int N = N; Args = {Args ...}; Ret = Ret; T = Derived]
     void build_function_tables(std::string name, Ret T::* func, Args&&... args) {
          ^
sol/userdata.hpp:114:10: note:   template argument deduction/substitution failed:
sol/userdata.hpp:134:30: note:   mismatched types ‘Derived’ and ‘Base’
         build_function_tables<0>(std::forward<Args>(args)...);

This is the full file's content:

//============================================================================
// Name        : my_test.cpp
// Author      : Bruno
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include "sol.hpp"

using namespace std;

class Base {
public:
    Base( int a_num ) : m_num( a_num ) { }

    int get_num( ) {
        return m_num;
    }

protected:
    int m_num;
};

class Derived : public Base {
public:
    Derived( int a_num ) : Base( a_num ) { }

    int get_num_10( ) {
        return 10 * m_num;
    }
};

int main() {
    sol::state l_lua;

    l_lua.open_libraries( sol::lib::debug, sol::lib::base, sol::lib::io );
    sol::constructors<sol::types<int>> l_ctor_base;
    sol::userdata<Base> l_userdata_base( "Base", l_ctor_base, "get_num", &Base::get_num );

    l_lua.set_userdata( l_userdata_base );

    l_lua.script( "base = Base.new( 5 )" );
    l_lua.script( "print( base:get_num() )" );

    sol::constructors<sol::types<int>> l_ctor_derived;
    sol::userdata<Derived> l_userdata_derived( "Derived", l_ctor_derived, "get_num", &Derived::get_num, "get_num_10", &Derived::get_num_10 );

    l_lua.set_userdata( l_userdata_derived );

    l_lua.script( "derived = Derived.new( 7 )" );
    l_lua.script( "print( derived:get_num_10() )" );
    l_lua.script( "print( derived:get_num() )" );

    cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!

    return 0;
}

Thanks for the help here: I managed to repro and fix it. Turns out GCC/Clang compilers want explicitly matching when the type is deduced by a template parameter, so we had to add an extra template argument so it could properly deduce either the same or some base type. A static_assert is used to prevent shenanigans from happening.

Pull request is up and fixes the problem. When it gets merged, you'll be good to go. Happy trails!

Glad to be of help :D

I believe this got fixed as of the last PR. Thanks for taking the time to submit an issue.