【问题标题】:Difficulty in verifying valide calls with boost::hana::is_valid难以使用 boost::hana::is_valid 验证有效调用
【发布时间】:2023-01-27 22:39:14
【问题描述】:

我有一个 Foo 类,它可以由 C 风格的字符串、字符串视图和非临时字符串构造(实际上它包含其他成员和方法,并且它以字符为模板传递给 basic_string*s 模板) :

struct Foo {
    explicit constexpr Foo()
        : text{}
    {}
    explicit constexpr Foo(std::string_view text)
        : text{std::move(text)}
    {}
    explicit constexpr Foo(char const* text)
        : Foo{std::string_view{text}}
    {}
    explicit constexpr Foo(char* text)
        : Foo{std::string_view{text}}
    {}
    explicit constexpr Foo(std::string&&) = delete;

    std::string_view text;
};

在 Boost.Hana 的帮助下,出于文档目的,我可以断言 Foo 可以由什么构建,什么不能,在测试中:

for_each(make_basic_tuple(
            type_c<std::string>,
            // clearly I'm not also listing type_c<int> and all the countless imaginable types that wouldn't work
            type_c<std::string&&>
            ),
        [](auto t){
            static_assert(!std::is_constructible_v<Foo, typename decltype(t)::type>);
        });
                                                                                      
for_each(make_basic_tuple(
            type_c<char*>,
            type_c<char const*>,
            // ...
            type_c<std::string_view>,
            type_c<std::string const&>
            ),
        [](auto t){
            static_assert(std::is_constructible_v<Foo, typename decltype(t)::type>);
        });

但是通过 Boost.Hana,也定义了一个 make_line 辅助函数:

namespace boost::hana {
template <>
struct make_impl<Foo> {
    static constexpr Foo apply(const char* text) {
        return Foo{text};
    }
    static constexpr Foo apply(std::string const& text) {
        return Foo{text};
    }
    static constexpr Foo apply(std::string_view text) {
        return Foo{std::move(text)};
    }
    static constexpr Foo apply(std::string&&) = delete;
};
}

inline constexpr auto make_foo = boost::hana::make<Foo>;

我可以很容易地验证它只适用于参数的预期类别值:

make_foo("");
make_foo(""sv);
make_foo(sv);
make_foo(s);
//make_foo(std::move(s)); // correctly doesn't compile
//make_foo(""s);          // correctly doesn't compile

但是,我无法通过 hana::is_valid 在测试中编写此代码。这是我失败的尝试:

std::string s{};
std::string_view sv{};
                                                                                        
constexpr auto can_make_foo_from =
    is_valid([](auto&& obj) -> decltype(make_foo(std::forward<decltype(obj)>(obj))){});
                                                                                        
static_assert( decltype(can_make_foo_from(""))::value);
static_assert( decltype(can_make_foo_from(""sv))::value);
static_assert( decltype(can_make_foo_from(sv))::value);
static_assert( decltype(can_make_foo_from(s))::value);
//static_assert(!decltype(can_make_foo_from(std::move(s)))::value);
//static_assert(!decltype(can_make_foo_from(""s))::value);

在我的意图中,最后两行应该编译,但它们没有。

Here's the full example on Compiler Explorer

【问题讨论】:

    标签: c++ c++17 template-meta-programming sfinae boost-hana


    【解决方案1】:

    boost/hana/fwd/core/make.hpp我们可以看到:

    template <typename Tag>
    struct make_t {
        template <typename ...X>
        constexpr decltype(auto) operator()(X&& ...x) const {
            return make_impl<Tag>::apply(static_cast<X&&>(x)...);
        }
    };
    
    template <typename Tag>
    BOOST_HANA_INLINE_VARIABLE constexpr make_t<Tag> make{};
    

    decltype(auto) 不会触发 SFINAE。

    所以任何 make&lt;MyType&gt;(Ts...) 都是有效的,但会产生硬错误。

    修复将是:

    template <typename Tag>
    struct make_t {
        template <typename ...X>
        constexpr auto operator()(X&& ...x) const
        -> decltype(make_impl<Tag>::apply(static_cast<X&&>(x)...))
        {
            return make_impl<Tag>::apply(static_cast<X&&>(x)...);
        }
    };
    

    Demo

    【讨论】:

      猜你喜欢
      • 2021-01-09
      • 1970-01-01
      • 2021-08-08
      • 2023-03-23
      • 1970-01-01
      • 2015-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多