`boost::hana` 模板函数的内省
`boost::hana` introspection for templated function
我想知道某个类型是否定义了带有模板参数的成员函数,但模板参数受 SFINAE 约束。
示例我有一个类型 A
,只有一个函数 foo
struct A{
template<typename T>
std::enable_if<Condition<T>,ReturnType> foo(T t){ ... }
};
Condition
是一些条件,例如std::is_pos_v
现在我正在使用 boost::hana::is_valid
来确定类型是否具有成员函数,例如 foo()
或 foo(int)
但是当使用模板参数时我迷路了。
我想写这样的东西
auto has_foo = hana::is_valid([](auto t) -> delctype(hana::traits::declval(t).foo(???)){});
has_foo(hana::type_c<A>); // <-- I want this to return true
问题是我应该用什么代替 ???
?
编译器可能无法 "prove" 类型 A
满足:"For every type T
which satisfy Condition
there is a member function A::foo(T)
"
所以为了让编译器更容易,我很乐意至少 "prove" 对于类型 A
持有:"There is a type T
such that there is a member function A::foo(T)
"
不幸的是,这在我的示例中仍然很难,因为这需要证明存在满足 Condition
.
的类型
这样是不是可以为了反省而忽略SFIANE?然后我可以选择一个任意类型并测试是否存在,例如A::foo(int)
.
如前所述,除了编写编译器插件和自己遍历 AST 之外,没有为这种自省提供的工具。
如果您提供具体的 T
来构成完整有效的表达式,您当然可以使用 hana::is_valid
。
我提供了一个额外的例子,允许提供一个 "concept" 假设某种设施为你输入的任何 "concept" 提供一个具体的 T
。这有点像虽然达到了。
#include <boost/hana.hpp>
#include <type_traits>
#include <utility>
namespace hana = boost::hana;
using hana::Sequence;
struct A {
template <typename T>
std::enable_if_t<Sequence<T>::value, void> foo(T) { }
};
struct B {
template <typename T>
void bar(T) { }
};
template <typename T>
auto has_foo_1 = hana::is_valid([](auto&& a)
-> decltype(std::forward<decltype(a)>(a).foo(std::declval<T>())) { });
template <template <typename, typename> typename Concept>
auto declval_concept_impl = int{};
template <>
auto declval_concept_impl<Sequence> = hana::tuple<>{};
template <template <typename, typename> typename Concept>
using declval_concept = std::add_rvalue_reference_t<decltype(declval_concept_impl<Concept>)>;
template <template <typename, typename> typename Concept>
auto has_foo_2 = hana::is_valid([](auto&& a)
-> decltype(std::forward<decltype(a)>(a).foo(declval_concept<Concept>{})) { });
int main() {
A a;
B b;
static_assert( has_foo_1<hana::tuple<>>(a));
static_assert(not has_foo_1<hana::tuple<>>(b));
static_assert( has_foo_2<Sequence>(a));
static_assert(not has_foo_2<Sequence>(b));
}
我想知道某个类型是否定义了带有模板参数的成员函数,但模板参数受 SFINAE 约束。
示例我有一个类型 A
,只有一个函数 foo
struct A{
template<typename T>
std::enable_if<Condition<T>,ReturnType> foo(T t){ ... }
};
Condition
是一些条件,例如std::is_pos_v
现在我正在使用 boost::hana::is_valid
来确定类型是否具有成员函数,例如 foo()
或 foo(int)
但是当使用模板参数时我迷路了。
我想写这样的东西
auto has_foo = hana::is_valid([](auto t) -> delctype(hana::traits::declval(t).foo(???)){});
has_foo(hana::type_c<A>); // <-- I want this to return true
问题是我应该用什么代替 ???
?
编译器可能无法 "prove" 类型 A
满足:"For every type T
which satisfy Condition
there is a member function A::foo(T)
"
所以为了让编译器更容易,我很乐意至少 "prove" 对于类型 A
持有:"There is a type T
such that there is a member function A::foo(T)
"
不幸的是,这在我的示例中仍然很难,因为这需要证明存在满足 Condition
.
这样是不是可以为了反省而忽略SFIANE?然后我可以选择一个任意类型并测试是否存在,例如A::foo(int)
.
如前所述,除了编写编译器插件和自己遍历 AST 之外,没有为这种自省提供的工具。
如果您提供具体的 T
来构成完整有效的表达式,您当然可以使用 hana::is_valid
。
我提供了一个额外的例子,允许提供一个 "concept" 假设某种设施为你输入的任何 "concept" 提供一个具体的 T
。这有点像虽然达到了。
#include <boost/hana.hpp>
#include <type_traits>
#include <utility>
namespace hana = boost::hana;
using hana::Sequence;
struct A {
template <typename T>
std::enable_if_t<Sequence<T>::value, void> foo(T) { }
};
struct B {
template <typename T>
void bar(T) { }
};
template <typename T>
auto has_foo_1 = hana::is_valid([](auto&& a)
-> decltype(std::forward<decltype(a)>(a).foo(std::declval<T>())) { });
template <template <typename, typename> typename Concept>
auto declval_concept_impl = int{};
template <>
auto declval_concept_impl<Sequence> = hana::tuple<>{};
template <template <typename, typename> typename Concept>
using declval_concept = std::add_rvalue_reference_t<decltype(declval_concept_impl<Concept>)>;
template <template <typename, typename> typename Concept>
auto has_foo_2 = hana::is_valid([](auto&& a)
-> decltype(std::forward<decltype(a)>(a).foo(declval_concept<Concept>{})) { });
int main() {
A a;
B b;
static_assert( has_foo_1<hana::tuple<>>(a));
static_assert(not has_foo_1<hana::tuple<>>(b));
static_assert( has_foo_2<Sequence>(a));
static_assert(not has_foo_2<Sequence>(b));
}