Следующее выражение, использующее is_assignable
, возвращает true
при использовании gcc 4.7 и boost 1.49:
typedef boost::function<void()> F;
std::is_assignable<F, std::nullptr_t>::value
Однако этот код не скомпилируется:
boost::function<void()> f;
f = nullptr;
создавая эти сообщения об ошибках:
In file included from c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/function/detail/maybe_include.hpp:13:0,
from c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/function/detail/function_iterate.hpp:14,
from c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/preprocessor/iteration/detail/iter/forward1.hpp:47,
from c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/function.hpp:64,
from ..\main.cpp:8:
c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/function/function_template.hpp: In instantiation of 'static void boost::detail::function::void_function_obj_invoker0<FunctionObj, R>::invoke(boost::detail::function::function_buffer&) [with FunctionObj = std::nullptr_t; R = void]':
c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/function/function_template.hpp:907:60: required from 'void boost::function0<R>::assign_to(Functor) [with Functor = std::nullptr_t; R = void]'
c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/function/function_template.hpp:722:7: required from 'boost::function0<R>::function0(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = std::nullptr_t; R = void; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]'
c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/function/function_template.hpp:1042:16: required from 'boost::function<R()>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = std::nullptr_t; R = void; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]'
c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/function/function_template.hpp:1083:5: required from 'typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R()>&>::type boost::function<R()>::operator=(Functor) [with Functor = std::nullptr_t; R = void; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R()>&>::type = boost::function<void()>&]'
..\main.cpp:172:6: required from here
c:\mingw\bin\../lib/gcc/i686-pc-mingw32/4.7.0/../../../../include/boost/function/function_template.hpp:153:11: error: '* f' cannot be used as a function
Кроме того, это выражение возвращает false
:
typedef boost::function<void()> G;
std::is_assignable<G, decltype(NULL)>::value
но этот код компилируется:
boost::function<void()> g;
g = NULL;
Результаты is_assignable
, похоже, не отражают функциональность boost::function
. Я здесь что-то не так? (У меня возникли проблемы с пониманием сообщений об ошибках.)
Я думал, что черты типа должны быть надежным способом определения функциональности классов, используемых в шаблонах. Являются ли свойства типа, представленные на С++ 11, просто несовместимыми с функцией boost:: function?
Чтобы дать этот контекст, я работал над несколькими личными проектами, чтобы лучше ознакомиться с новыми функциями С++ 11. Для этого конкретного проекта я пытаюсь создать класс, который хранит вызываемую функцию, которая может быть "деактивирована". Это примерно то, что я пытаюсь сделать:
template <typename F>
class callable_function
{
public:
callable_function(F func) : func_(func)
{
/* func_ is initially active */
}
void call()
{
if (/* func_ is active */) func_();
}
void deactivate()
{
/* set func_ to deactive */
}
private:
F func_;
};
Для блоков /* func_ is active */
и /* set func_ to deactive */
я хочу предоставить две различные реализации, которые выбираются во время компиляции в зависимости от свойств F
. Если nullptr
может быть назначен func_
и func_
может использоваться в булевом контексте, тогда я хочу использовать следующее (это то, что выбирается для встроенных указателей функций и std::function
):
template <typename F>
class callable_function
{
public:
callable_function(F func) : func_(func) {}
void call()
{
if (func_) func_();
}
void deactivate()
{
func_ = nullptr;
}
private:
F func_;
};
Если nullptr
не может быть присвоено func_
, тогда я хочу сохранить дополнительное логическое значение в классе, в котором хранится "активный" статус. Эта реализация выбрана для функторов и лямбда-функций:
template <typename F>
class callable_function
{
public:
callable_function(F func) : func_(func), active_(true) {}
void call()
{
if (active_) func_();
}
void deactivate()
{
active_ = false;
}
private:
F func_;
bool active_;
};
Так как nullptr
в настоящее время нельзя назначить boost::function
, я бы ожидал, что вторая реализация будет выбрана. Однако, поскольку is_assignable
возвращает true
для boost::function
и nullptr
, вместо этого выбирается первая реализация, что приводит к ошибке компиляции в функции deactivate
.