Я пытался уменьшить эту проблему, насколько я могу.
Если я раскомментирую void initialize()
, то этот код компилируется. Если я оставлю его закомментированным, то он не будет построен.
Единственный способ, который я нашел, чтобы решить эту проблему, это собрать в режиме C ++ 03 с boost::shared_ptr
вместо std::shared_ptr
,
Я попытался с помощью стандартного компилятора clang на OS X Lion (с libc ++) и следующих компиляторов на CentOS 6.4 x64:
/opt/llvm/3.2/bin/clang++ -gcc-toolchain /opt/gcc/4.7.2 -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG
/opt/llvm/3.1/bin/clang++ -gcc-toolchain /opt/gcc/4.7.2 -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG
/opt/llvm/3.0/bin/clang++ -gcc-toolchain /opt/gcc/4.7.2 -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG
/opt/gcc/4.7.2/bin/g++ -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG
/opt/gcc/4.7.1/bin/g++ -std=gnu++11 foo.cc -I/opt/boost/1.53.0/include -DBOOST_SPIRIT_USE_PHOENIX_V3 -DBOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT -DBOOST_SPIRIT_DEBUG
Как обычно, вывод компилятора из Spirit довольно многословен, поэтому я включил его в виде сущности:
#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <memory>
class Object {
public:
void initialize(std::vector<int>) {
}
//void initialize() {
//}
};
int main() {
boost::spirit::qi::rule<std::string::iterator, int()> integer;
boost::spirit::qi::rule<std::string::iterator, std::shared_ptr<Object>()> object;
using boost::phoenix::bind;
using boost::spirit::_val;
using boost::spirit::_1;
object
= (*integer) [bind(&Object::initialize, *_val, _1)];
}
#define BOOST_SPIRIT_USE_PHOENIX_V3
Исправляет это для меня. И изменить *val
чтобы просто val
потому что Феникс будет знать, как привязать функцию-член к нему.
ОБНОВИТЬ Как намекнул @llonesmiz, оказывается, что это действительно связано с ADL. Хотя отношение очень тонкое.
std::vector<>
в тип указатель на член-функцию заставляет ADL искать пространство имен std и находить std::bind
, вместо phoenix::bind
, val
, вместо *val
Компилятор выбирает феникса bind
как лучший матч.int
(вместо типа из std
namespace), проблема исчезает, и привязка Phoenix всегда выбирается.Вы можете увидеть вышеприведенные наблюдения, проверив вывод эта минимальная тестовая программа который сбрасывает typeid различных выражений связывания (и запускает их через c++filt
)
Посмотрите это в прямом эфире с GCC на http://liveworkspace.org/code/idDtv$0
Обновить Clang, похоже, нравится только с boost::shared_ptr
вместо: http://liveworkspace.org/code/idDtv$3. Я могу только предположить, что это связано с различиями в libc ++ (?)
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix.hpp>
#include <memory>
class Object {
public:
void initialize(std::vector<int>) {
}
};
int main() {
boost::spirit::qi::rule<std::string::iterator, int()> integer;
boost::spirit::qi::rule<std::string::iterator, std::shared_ptr<Object>()> object;
using boost::phoenix::bind;
using boost::spirit::_val;
using boost::spirit::_1;
object
= (*integer) [bind(&Object::initialize, _val, _1)];
}
Других решений пока нет …