【问题标题】:Why cannot concepts be passed to template meta-functions?为什么不能将概念传递给模板元函数?
【发布时间】:2021-10-05 20:25:59
【问题描述】:

考虑 Boost.MP11、Brigand 等库提供的任何常见类型级算法... 例如:

template<typename... Args>
struct TypeList;

using my_types = TypeList<int, float, char, float, double>;

constexpr int count = boost::mp11::mp_count_if<my_types, std::is_floating_point>::value;
// this holds:
static_assert(count == 3);

注意std::is_floating_point 可以定义为:

template<typename T>
struct is_floating_point { constexpr bool value = __compiler_magic(T); };

同样,我们有std::floating_point 概念

template<typename T>
concept floating_point = requires (T t) { __other_compiler_magic(T); };

遗憾的是,尽管有相似之处,但如果不为概念引入手动命名的包装器,似乎没有一种简单的方法可以编写这样的东西:

constexpr int count = boost::mp11::count_if<my_types, std::floating_point>::value;

我的问题是:为什么此时不能传递概念来代替类型?是缺乏标准化,还是这些库可以通过提供更多重载来解决?

看起来每个概念都必须包装在一个模板类型中,该类型只会在其模板参数上调用该概念。

从外部看,概念就像元函数,其域是 {set of types} -> bool。编译器能够延迟将参数传递给“传统”基于类型的元函数,例如std::is_floating_point,为什么概念上似乎不能发生同样的情况?

【问题讨论】:

    标签: c++ c++20 template-meta-programming c++-concepts


    【解决方案1】:

    字面意思是我们有模板模板参数但没有概念模板参数,所以你不能将概念作为模板参数传递。

    另一个字面上的回答是,它从来都不是最初概念提案的一部分,也没有人努力建议它作为扩展(尽管我一直是collecting use-cases)。

    必须回答的一件事是依赖概念如何影响包容 - 因为目前使用的概念从来都不是依赖的,所以弄清楚包容很简单(实际上,它仍然一点也不简单,但至少你的所有事情需要就在那里)。但在这样的场景中:

    template <template <typename> concept C, typename T> 
        requires C<T>
    void foo(T); // #1
    
    template <typename T>
    void foo(T); // #2
    

    如果#1 可行,您可能想说它比#2 更好,因为它仍然受到限制,而另一个则没有。也许那是微不足道的。但后来:

    template <template <typename> concept C, typename T> 
        requires C<T>
    void bar(T); // #3
    
    template <OtherConcept T>
    void bar(T); // #4
    

    假设#3#4 都是可行的,可以说哪个更好吗?我们通常说整个过载总是比不同的过载更好 - 但这里可能并非如此。也许这只是模棱两可?

    在我看来,这是获取概念模板参数需要回答的主要问题。

    另一个问题可能是,我可以写foo&lt;convertible_to&lt;int&gt;&gt;(42)convertible_to&lt;int&gt; 并不是真正的一元概念,但它是一个 type-constraint,在某些情况下被视为一个,所以我仍然希望它能够工作。


    一旦我们有了这样的东西,我相信 Boost.Mp11 会很快获得类似的东西:

    template <template <typename...> concept C>
    struct mp_quote_c {
        template <typename... T>
        using fn = mp_bool<C<T...>>;
    };
    

    这样你就可以写了:

    constexpr int count = mp_count_if_q<my_types, mp_quote_c<std::floating_point>>::value;
    

    【讨论】:

      猜你喜欢
      • 2020-03-11
      • 1970-01-01
      • 2019-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多