我有一个调用回调函数的函数,该函数接受一个仅可移动的类型(例如unique_ptr
)。
template <typename Function>
void foo(const Function& function) {
BOOST_CONCEPT_ASSERT((
boost::UnaryFunction<Function, void, std::unique_ptr<Bar>));
auto bar = std::make_unique<Bar>();
...
function(std::move(bar));
}
尝试编译此代码时,我收到一条消息,BOOST_CONCEPT_ASSERT
行尝试复制unique_ptr
。如果我删除该行,代码工作正常。似乎Boost.Concept库不支持移动语义。如果没有编写我自己的概念类(顺便提一下,支持左值和右值作为参数,并不是很简单),是否有任何解决方法。
答案 0 :(得分:2)
#include <type_traits>
#include <utility>
template <typename...>
struct voider { using type = void; };
template <typename... Ts>
using void_t = typename voider<Ts...>::type;
template <typename, typename = void_t<>>
struct is_callable : std::false_type {};
template <typename F, typename... Args>
struct is_callable<F(Args...), void_t<decltype(std::declval<F>()(std::declval<Args>()...))>> : std::true_type {};
//...
static_assert(is_callable<Function&(std::unique_ptr<Bar>)>{}, "Not callable");
答案 1 :(得分:2)
那是对的。不幸的是,UnaryFunction
作为一个概念写成:
BOOST_concept(UnaryFunction,(Func)(Return)(Arg))
{
BOOST_CONCEPT_USAGE(UnaryFunction) { test(is_void<Return>()); }
private:
void test(boost::mpl::false_)
{
f(arg); // "priming the pump" this way keeps msvc6 happy (ICE)
Return r = f(arg);
ignore_unused_variable_warning(r);
}
void test(boost::mpl::true_)
{
f(arg); // <== would have to have std::move(arg)
// here to work, or at least some kind of
// check against copy-constructibility, etc.
}
#if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \
&& BOOST_WORKAROUND(__GNUC__, > 3)))
// Declare a dummy construktor to make gcc happy.
// It seems the compiler can not generate a sensible constructor when this is instantiated with a refence type.
// (warning: non-static reference "const double& boost::UnaryFunction<YourClassHere>::arg"
// in class without a constructor [-Wuninitialized])
UnaryFunction();
#endif
Func f;
Arg arg;
};
由于arg
由左值传递,因此无法使用Boost.Concepts。直。你可以写一个黑客。由于我们只是调用检查f(arg)
是否有效,因此我们可以为arg
构建一个可转换为unique_ptr<Bar>
的本地类型。那就是:
template <typename Function>
void foo(Function f)
{
struct Foo {
operator std::unique_ptr<int>();
};
BOOST_CONCEPT_ASSERT((
boost::UnaryFunction<Function, void, Foo>));
f(std::make_unique<int>(42));
}
或更一般地说:
template <typename T>
struct AsRvalue {
operator T(); // no definition necessary
};
template <typename Function>
void foo(Function f)
{
BOOST_CONCEPT_ASSERT((
boost::UnaryFunction<Function, void, AsRvalue<std::unique_ptr<int>>>));
f(std::make_unique<int>(42));
}
在gcc和clang上为我编译(虽然在clang上发出了关于未使用的typedef的警告)。然而,在那时,可能更清楚的是只写出自己的概念以使其发挥作用。像Piotr's这样的东西最容易。