Связывание функций с несколькими аргументами приводит к ошибке C2027.

Я использую ChaiScript 5.3.1 и пытаюсь связать функции с моим собственным классом, в частности функцию setPosition, которая может принимать либо Vector3, либо 3 числа с плавающей запятой.

Класс и его соответствующие методы объявлены так:

class DLLExport Actor
{
public:
        Actor(Level* level, const String& name, Actor* parent);
        virtual ~Actor();

        void setPosition(const Real& x, const Real& y, const Real& z);
        void setPosition(const Vector3& position);
};

и я пытаюсь связать их так:

m->add(user_type<Actor>(), "Actor");
m->add(fun<void (Actor::*)(const Vector3&)>(&Actor::setPosition), "setPosition");

Это приводит к следующему выводу компилятора (Windows, MSVC 2013):

 2functional(550): error C2027: use of undefined type 'std::_Get_function_impl<_Fty>'
 2>          with
 2>          [
 2>              _Fty=void (__thiscall Actor::* )(const Vector3 &)
 2>          ]
 2>          ..\..\ScriptingDemo\Binder.cpp(60) : see reference to class template instantiation 'std::function<void (__thiscall Actor::* )(const Vector3 &)>' being compiled
 2functional(551): error C2504: 'type' : base class undefined
 2functional(554): error C2027: use of undefined type 'std::_Get_function_impl<_Fty>'
 2>          with
 2>          [
 2>              _Fty=void (__thiscall Actor::* )(const Vector3 &)
 2>          ]
 2functional(554): error C2146: syntax error : missing ';' before identifier '_Mybase'
 2functional(554): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

person Ilija Boshkov    schedule 25.08.2014    source источник
comment
Является ли fun таким же, как std::function<T> ?   -  person Piotr Skotnicki    schedule 25.08.2014
comment
Нет, fun — это функция ChaiScript (точнее, я использую ее из chaiscript::Module(ptr)) См. это: chaiscript.com/docs/5/   -  person Ilija Boshkov    schedule 25.08.2014
comment
Я основываю свой подход на деталях, определенных здесь: chaiscript.com/docs/5/ index.html#addingfunctions (привязка перегруженной функции)   -  person Ilija Boshkov    schedule 25.08.2014
comment
Каким-то образом где-то у вас есть typedef или макрос, который делает fun означающим std::function. Вы не вызываете chaiscript::fun. Выясните, почему.   -  person Igor Tandetnik    schedule 25.08.2014
comment
@igor-tandetnik Да, похоже, в этом конкретном определении использовалась функция std::function. Я просмотрел определения, и вот что появилось: i.imgur.com/4Ye1nuC.png. Теперь нужно выяснить, как на самом деле связать функцию, не связывая ее с конкретным объектом.   -  person Ilija Boshkov    schedule 25.08.2014
comment
Этот [ответ] (stackoverflow.com/a/7582574/878466) кажется указывает на то, что это способ сделайте это: std::function<void(Actor*, Vector3&)> setPos = &Crimson::Actor::setPosition; (адаптировано из информации в ответе, за который проголосовали)   -  person Ilija Boshkov    schedule 25.08.2014


Ответы (2)


Это ошибка компилятора. И Clang, и GCC принимают это SSCCE, а Visual C++ — нет.

Четыре перегруженные функции chaiscript::fun объявлены так:

/*1*/ template <typename T>
      Proxy_Function fun (T t);

/*2*/ template <typename T>
      Proxy_Function fun (const std::function< T > &f);

/*3*/ template <typename T, typename Q>
      Proxy_Function fun (T t, const Q &q);

/*4*/ template <typename T, typename Q, typename R>
      Proxy_Function fun (T t, const Q &q, const R &r);

Согласно правилам языка, это выражение:

fun<void (Actor::*)(const Vector3&)>(&Actor::setPosition)

Результатом является вызов либо перегрузки 1, либо перегрузки 2, разрешение перегрузки будет определять, что именно.

После подстановки явного аргумента шаблона вот с чем придется работать при разрешении перегрузки:

/*1*/ Proxy_Function fun (void (Actor::*)(const Vector3&) t);
/*2*/ Proxy_Function fun (const std::function< void (Actor::*)(const Vector3&) > &f);

std::function< void (Actor::*)(const Vector3&) > — это неопределенный тип, поэтому перегрузка 2 невозможна. Visual C++, похоже, считает, что это ошибка, но это не так.

С вашим обходным путем:

fun((void(Actor::*)(const Vector3&))&Actor::setPosition)

Вы приводите указатель на перегруженную функцию-член &Actor::setPosition к типу void(Actor::*)(const Vector3&) и разрешаете вывод аргументов шаблона, и Visual C++ этим доволен.

Вам было бы еще лучше избегать приведения C-стиля:

fun(static_cast<void(Actor::*)(const Vector3&)>( &Actor::setPosition ))
person Oktalist    schedule 25.08.2014

Не уверен, как именно, но я исправил это так:

m->add(fun((void(Actor::*)(const Vector3&))&Actor::setPosition), "setPosition");

Я просто рад, что нашел ответ, если бы кто-нибудь объяснил, почему это работает, было бы здорово.

person Ilija Boshkov    schedule 25.08.2014