You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用boost::hana::is_valid验证make_foo合法调用遇阻

问题根源

boost::hana::is_valid的判断逻辑是检查表达式能否推导出有效类型,而非验证表达式是否能实际执行。当你传入std::string&&(比如std::move(s)或""s)时,重载决议会匹配到被删除的make_impl<Foo>::apply(std::string&&),虽然这个函数不可调用,但decltype(make_foo(std::move(s)))仍能得到合法的Foo类型,因此is_valid错误地返回true。

解决方案

方案1:C++20及以上(推荐)

结合requires表达式增强检查逻辑,同时验证表达式的可调用性:

constexpr auto can_make_foo_from =
    hana::is_valid([](auto&& obj) -> decltype(auto) {
        // 额外检查表达式是否可实际调用
        requires requires { make_foo(std::forward<decltype(obj)>(obj)); };
        return make_foo(std::forward<decltype(obj)>(obj));
    });

方案2:兼容C++17

使用std::is_invocable_v直接判断函数是否可调用:

#include <type_traits>

constexpr auto can_make_foo_from = [](auto&& obj) constexpr {
    using ArgT = decltype(std::forward<decltype(obj)>(obj));
    return std::is_invocable_v<decltype(make_foo)&, ArgT>;
};

修正后的测试代码(以C++20方案为例)

#include <boost/hana.hpp>
#include <string>
#include <string_view>

namespace hana = boost::hana;

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;
};

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>;

// 修正后的检查逻辑
constexpr auto can_make_foo_from =
    hana::is_valid([](auto&& obj) -> decltype(auto) {
        requires requires { make_foo(std::forward<decltype(obj)>(obj)); };
        return make_foo(std::forward<decltype(obj)>(obj));
    });

int main() {
    std::string s{};
    std::string_view sv{};
                                                                                        
    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);
}
原理说明
  • 方案1的requires表达式会直接验证make_foo(...)是否能合法调用,排除了被删除函数的干扰。
  • 方案2的std::is_invocable_v会检查给定的参数能否调用目标函数,自动忽略被删除或不可访问的重载。

内容的提问来源于stack exchange,提问作者Enlico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 18:40:56