[英]How to compare types (including ref-qualifiers) in a parameter pack and the types of std::function parameters
I'm storing an std::function
inside a variadic class template (passed in the constructor of the class).我将std::function
存储在可变参数 class 模板中(在类的构造函数中传递)。
While doing so, I want to check that the types of the std::function
parameters are the same as the types within the parameter pack of the class template.这样做时,我想检查std::function
参数的类型是否与 class 模板的参数包中的类型相同。 Here is an example:这是一个例子:
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
}
If a class Foo<int&>
is defined with a reference type, I'd like to make sure that the lambda also takes an int
by reference and not by value.如果 class Foo<int&>
是用引用类型定义的,我想确保 lambda 也通过引用而不是按值获取int
。
The other way around ( Foo<int>
and lambda with an int&
) already does not compile as that lambda cannot be converted to a function taking an int
by value.反过来( Foo<int>
和 lambda 带有int
int&
)已经无法编译,因为 lambda 不能通过输入转换为 ZC1C425268E68385D1AB5074C17A94F14 。
Using a static_assert()
, I tried to ensure that the type of the parameter in the lambda matches the type given as a template parameter to Foo
.使用static_assert()
,我试图确保 lambda 中的参数类型与作为模板参数给定的类型匹配Foo
。
So far, I have tried unwrapping the function arguments:到目前为止,我已经尝试解开 function arguments:
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, "");
...
Is there a way to achieve what I want?有没有办法实现我想要的? (Does it even make sense for me to think about such a check on my end, or should someone using my class Foo
make sure, that he provides a lambda with the correct parameter types?) (对我来说,考虑这样的检查是否有意义,或者是否应该有人使用我的class Foo
确保他提供了具有正确参数类型的 lambda?)
If you can use C++17... what about using the CTAD defined for std::function
to check that the std::function
deduced for the argument of the constructor is exactly the same of func
?如果您可以使用 C++17... 使用为std::function
来检查std::function
是否与为构造函数的参数推导的func
完全相同?
I mean... what about as follows?我的意思是……下面呢?
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;
};
Using this Foo
you get使用这个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
--- EDIT --- - - 编辑 - -
The OP observe that OP观察到
Foo<void(int&)> fooD([](auto&) {});
would not compile不会编译
Unfortunately, this solution impose a std::function
parameters CTAD deduction, so gives a compilation error when the argument is a generic lambda.不幸的是,这个解决方案强加了一个std::function
参数 CTAD 推导,所以当参数是通用 lambda 时会给出编译错误。
We can SFINAE deactivate the static_assert()
in case the std::function
is not deducible如果std::function
不可推断,我们可以 SFINAE 停用static_assert()
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;
};
So所以
Foo<int &> fooF([](auto &){});
become compilable.变得可编译。
Continue to gives an error a generic lambda receiving a generic reference when a value is requested继续给出错误一个通用 lambda 在请求值时接收通用引用
//Foo<int> fooD([](auto &){}); // compilation error (assigning func)
because remain the error assigning func
.因为仍然是分配func
的错误。
The problem is that, deactivating the test, the following code compile问题是,停用测试,以下代码编译
Foo<int &> fooE([](auto){}); // compile (!)
and I don't know how to avoid it.我不知道如何避免它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.