`boost :: hana`对模板化函数的内省

时间:2018-04-10 14:03:50

标签: c++ templates template-meta-programming introspection boost-hana

我想知道一个类型是否使用模板参数定义了一个成员函数,但模板参数是否受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)等成员函数,但是当模板参数I&#39; m丢失时。

我想写这样的东西

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

问题是我应该放什么而不是???

编译器可能无法证明&#34;类型A满足:&#34;对于满足T的每个类型Condition,都有一个成员函数A::foo(T)&#34;

因此,为了使编译器更容易,我很乐意至少&#34;证明&#34;类型为A的情况:&#34;类型为T,因此存在成员函数A::foo(T)&#34;

不幸的是,在我的示例中这仍然很难,因为这需要证明存在满足Condition的类型。

因此,内省的目的是否可以忽略SFIANE?然后我可以选择任意类型并测试例如A::foo(int)

1 个答案:

答案 0 :(得分:2)

如前所述,除了编写编译器插件并自己走AST之外,没有为这种内省提供设施。

如果您提供具体的T来制作完整有效的表达方式,您当然可以使用hana::is_valid

我提供了一个额外的例子,允许提供一个“概念”,假设某种设施可以为你输入的任何“概念”提供一个具体的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));
}