如何比较参数包中的类型(包括引用限定符)和 std::function 参数的类型
How to compare types (including ref-qualifiers) in a parameter pack and the types of std::function parameters
我将 std::function
存储在可变 class 模板中(在 class 的构造函数中传递)。
在执行此操作时,我想检查 std::function
参数的类型是否与 class 模板的参数包中的类型相同。这是一个例子:
template<typename... T>
class Foo {
public:
explicit Foo(std::function<void(T...)> f)
: func(std::move(f)) {
// static_assert(...) How to formulate the static_assert here?
}
std::function<void(T...)> func;
};
int main()
{
Foo<int> fooA([](int& a){}); // does not compile
Foo<int&> fooB([](int a){}); // should not compile, but does
Foo<int&> fooC([](int& a){}); // should compile
}
如果 class Foo<int&>
是用引用类型定义的,我想确保 lambda 也通过引用而不是值来获取 int
。
反过来(Foo<int>
和带有 int&
的 lambda)已经无法编译,因为 lambda 无法转换为按值采用 int
的函数。
使用 static_assert()
,我试图确保 lambda 中的参数类型与作为模板参数给定的类型匹配 Foo
。
到目前为止,我已尝试解包函数参数:
template<typename... T>
struct ID {};
template<typename Func>
struct Unwrap;
template<typename R, typename... Args>
struct Unwrap<R(Args...)> {
using ArgsType = ID<Args...>;
};
template<typename R, typename... Args>
struct Unwrap<std::function<R(Args...)>>
: Unwrap<R(Args...)> {};
...
static_assert(std::is_same<typename Unwrap<std::function<void(T...)>>::ArgsType, ID<T...>>::value, "");
...
有没有办法实现我想要的? (我自己考虑这样的检查是否有意义,或者使用我的 class Foo
的人是否应该确保他提供了具有正确参数类型的 lambda?)
如果您可以使用 C++17...使用为 std::function
定义的 CTAD 来检查构造函数参数推导的 std::function
是否准确与 func
?
相同
我的意思是……下面呢?
template <typename... T>
struct Foo
{
template <typename L>
Foo (L && l) : func{ std::forward<L>(l) }
{
using T1 = decltype(func);
using T2 = decltype(std::function{std::forward<L>(l)});
static_assert( std::is_same_v<T1, T2>, "a better failure message, please" );
}
std::function<void(T...)> func;
};
使用这个Foo
你得到
//Foo<int> fooA([](int& a){}); // compilation error (assigning func)
//Foo<int&> fooB([](int a){}); // compilation error (static_assert failure)
Foo<int&> fooC([](int& a){}); // compile
--- 编辑 ---
OP 观察到
Foo<void(int&)> fooD([](auto&) {});
would not compile
不幸的是,此解决方案强加了一个 std::function
参数 CTAD 推导,因此当参数是通用 lambda 时会出现编译错误。
我们可以 SFINAE 停用 static_assert()
以防 std::function
不可推导
constexpr std::false_type Bar (...);
template <typename L>
constexpr auto Bar (L && l)
-> decltype( std::function{std::forward<L>(l)}, std::true_type{} );
template <typename... T>
struct Foo
{
template <typename L>
Foo (L && l) : func{ std::forward<L>(l) }
{
if constexpr ( decltype(Bar(std::forward<L>(l)))::value == true )
{
using T1 = decltype(func);
using T2 = decltype(std::function{std::forward<L>(l)});
static_assert( std::is_same_v<T1, T2>, "a better message, please" );
}
}
std::function<void(T...)> func;
};
所以
Foo<int &> fooF([](auto &){});
变得可编译。
在请求值时继续给出错误接收通用引用的通用 lambda
//Foo<int> fooD([](auto &){}); // compilation error (assigning func)
因为仍然存在分配 func
的错误。
问题是,停用测试,编译以下代码
Foo<int &> fooE([](auto){}); // compile (!)
而且我不知道如何避免它。
我将 std::function
存储在可变 class 模板中(在 class 的构造函数中传递)。
在执行此操作时,我想检查 std::function
参数的类型是否与 class 模板的参数包中的类型相同。这是一个例子:
template<typename... T>
class Foo {
public:
explicit Foo(std::function<void(T...)> f)
: func(std::move(f)) {
// static_assert(...) How to formulate the static_assert here?
}
std::function<void(T...)> func;
};
int main()
{
Foo<int> fooA([](int& a){}); // does not compile
Foo<int&> fooB([](int a){}); // should not compile, but does
Foo<int&> fooC([](int& a){}); // should compile
}
如果 class Foo<int&>
是用引用类型定义的,我想确保 lambda 也通过引用而不是值来获取 int
。
反过来(Foo<int>
和带有 int&
的 lambda)已经无法编译,因为 lambda 无法转换为按值采用 int
的函数。
使用 static_assert()
,我试图确保 lambda 中的参数类型与作为模板参数给定的类型匹配 Foo
。
到目前为止,我已尝试解包函数参数:
template<typename... T>
struct ID {};
template<typename Func>
struct Unwrap;
template<typename R, typename... Args>
struct Unwrap<R(Args...)> {
using ArgsType = ID<Args...>;
};
template<typename R, typename... Args>
struct Unwrap<std::function<R(Args...)>>
: Unwrap<R(Args...)> {};
...
static_assert(std::is_same<typename Unwrap<std::function<void(T...)>>::ArgsType, ID<T...>>::value, "");
...
有没有办法实现我想要的? (我自己考虑这样的检查是否有意义,或者使用我的 class Foo
的人是否应该确保他提供了具有正确参数类型的 lambda?)
如果您可以使用 C++17...使用为 std::function
定义的 CTAD 来检查构造函数参数推导的 std::function
是否准确与 func
?
我的意思是……下面呢?
template <typename... T>
struct Foo
{
template <typename L>
Foo (L && l) : func{ std::forward<L>(l) }
{
using T1 = decltype(func);
using T2 = decltype(std::function{std::forward<L>(l)});
static_assert( std::is_same_v<T1, T2>, "a better failure message, please" );
}
std::function<void(T...)> func;
};
使用这个Foo
你得到
//Foo<int> fooA([](int& a){}); // compilation error (assigning func)
//Foo<int&> fooB([](int a){}); // compilation error (static_assert failure)
Foo<int&> fooC([](int& a){}); // compile
--- 编辑 ---
OP 观察到
Foo<void(int&)> fooD([](auto&) {});
would not compile
不幸的是,此解决方案强加了一个 std::function
参数 CTAD 推导,因此当参数是通用 lambda 时会出现编译错误。
我们可以 SFINAE 停用 static_assert()
以防 std::function
不可推导
constexpr std::false_type Bar (...);
template <typename L>
constexpr auto Bar (L && l)
-> decltype( std::function{std::forward<L>(l)}, std::true_type{} );
template <typename... T>
struct Foo
{
template <typename L>
Foo (L && l) : func{ std::forward<L>(l) }
{
if constexpr ( decltype(Bar(std::forward<L>(l)))::value == true )
{
using T1 = decltype(func);
using T2 = decltype(std::function{std::forward<L>(l)});
static_assert( std::is_same_v<T1, T2>, "a better message, please" );
}
}
std::function<void(T...)> func;
};
所以
Foo<int &> fooF([](auto &){});
变得可编译。
在请求值时继续给出错误接收通用引用的通用 lambda
//Foo<int> fooD([](auto &){}); // compilation error (assigning func)
因为仍然存在分配 func
的错误。
问题是,停用测试,编译以下代码
Foo<int &> fooE([](auto){}); // compile (!)
而且我不知道如何避免它。