概念检查函数不适用于仅可移动参数
Concept checking a function doesn't work with movable-only arguments
我有一个函数,它调用一个回调函数,该函数接受仅可移动类型(例如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
。如果我去掉这行,代码就可以正常工作。似乎是助推。概念库不支持移动语义。如果不编写我自己的概念类(顺便说一句,支持左值和右值作为它们的参数并不是很简单(,有什么解决方法吗。
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一起工作。概念。直接地你可以写一个破解。由于我们只是调用检查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这样的东西最简单。
#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");
DEMO
相关文章:
- 在C++中,使用带有 std::optional 参数的函数<T>来表示可选参数是否有意义?
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 如何在不知道C++中有多少可选参数的情况下在循环中使用va_arg?
- 为什么协程的返回类型必须是可移动构造的?
- 通过跳过可选参数来填充参数包
- 我应该使我的局部变量常量还是可移动的
- 隐式可转换参数,但属于引用类型
- 有没有办法在 c++ 中显式调用可选参数?
- 对于参加可复制和可移动类的访问者来说,应该有多少过载?
- 已将 QSet 填充为可选参数
- 如何获取类型是否真正可移动可构造
- 可移动但不可复制的对象:按值传递还是按引用传递?
- const变量是否可以在具有默认值的参数中赋值(作为可选参数)
- 具有不同类型的可选参数的调用方函数
- 使用参数将仅可移动对象捕获到 lambda
- 从从可调用参数创建的线程对象参数移动构造 C++11 线程
- 使用 std::string 参数和不可移动/可复制参数构建 std::map
- std::带可移动、不可复制参数的线程
- 概念检查函数不适用于仅可移动参数
- std::线程构造函数中的可移动参数(Visual c++ 2012)