【问题标题】:partial specialised template as template argument部分专用模板作为模板参数
【发布时间】:2021-04-18 12:35:15
【问题描述】:

假设我有一个函数foo() 采用参数包Ts。但是,如果只有一种类型满足std::is_integral 的要求,该函数应该只接受参数包Ts。我编写的以下代码完全符合预期。

#include <type_traits>

template <template <typename> typename predicate, typename... Ts>
inline constexpr std::size_t count_if = ((predicate<Ts>::value ? 1 : 0) + ...);

// this method only compiles if exactly one of the given template arguments is of an integral type
template <typename... Ts>
void foo() requires (count_if<std::is_integral, Ts...> == 1) {}

int main()
{
    foo<int, double, float>(); //this compiles
    //foo<int, long, float>(); //this doesn't, as it should
}

但是,假设函数 foo() 正在由模板类型 T 的参数扩展,如下所示:

#include <type_traits>

template <template <typename> typename predicate, typename... Ts>
inline constexpr std::size_t count_if = ((predicate<Ts>::value ? 1 : 0) + ...);

// this method only compiles if one of the given template arguments is of an integral type
template <typename T, typename... Ts>
void foo(T) requires (count_if<std::is_integral, Ts...> == 1) {}

int main()

{
    foo<double, int, double, float>(double{}); //this compiles
    foo<int, int, double, float>(int{}); //this compiles
    //foo<double, int, long, float>(double{}); //this doesn't, as it should
}

现在我的问题是:是否有可能使我给我的count_if 函数的谓词依赖于我的函数foo() 的模板参数T

例如,我可以检查以下内容:

#include <type_traits>

template <template <typename> typename predicate, typename... Ts>
inline constexpr std::size_t count_if = ((predicate<Ts>::value ? 1 : 0) + ...);

template <typename T, typename... Ts>
void foo(T) requires (count_if<std::is_same<T, ?????> , Ts...> == 1) {}

int main()
{
    foo<double, int, double, float>(double{}); //this should compile, as there is exactly one type in parameter pack of type double
    foo<int, int, double, float>(int{}); //this should compile, as there is exactly one type in parameter pack of type int
    //foo<int, double, float>(); //this shouldn't compile, as there is no int in parameter pack
    //foo<double, double, double>(); //this shouldn't compile, as there are two doubles in paramter pack
}

这有可能吗?我尝试在函数体内使用static_assert() 对其进行检查,但我无法在其中定义模板结构,我需要它,因此我可以编写自己的谓词,例如:

template <typename T, typename... Ts>
void foo(T) 
{
  template <typename U>
  struct custom_predicate
  {
    static constexpr bool value = std::is_same<T, U>::value;
  };
    
  static_assert(count_if<custom_predicate, Ts...> == 1);
}

但就像我说的那样,这是不可能的,因为我无法在函数体内定义模板结构。

有人有想法吗?

【问题讨论】:

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


    【解决方案1】:

    在我看来你正在寻找

    template <template <typename, typename> typename predicate, typename T, typename... Ts>
    inline constexpr std::size_t count_if = ((predicate<T, Ts>::value ? 1 : 0) + ...);
    
    template <typename T, typename... Ts>
    void foo(T) requires (count_if<std::is_same, T, Ts...> == 1) {}
    

    但是,这样一来,您必须更改count_if 的要求。

    如果您想要(正如您在 static_assert() 示例中尝试的那样)生成特定的 is_same 来修复第一种类型,您可以编写类似于 custom_predicate 的内容,但在函数之外。

    例如

    template <template <typename> typename predicate, typename... Ts>
    inline constexpr std::size_t count_if = ((predicate<Ts>::value ? 1 : 0) + ...);
    
    template <typename T>
    struct my_predicate
     {
       template <typename U>
       using my_is_same = std::is_same<T, U>;
     };
    
    template <typename T, typename... Ts>
    void foo(T) requires (count_if<my_predicate<T>::template my_is_same, Ts...> == 1)
     { /* ... */ }
    

    或者也许,更灵活(并传递相同的std::is_same 作为参数)

    template <template <typename> typename predicate, typename... Ts>
    inline constexpr std::size_t count_if = ((predicate<Ts>::value ? 1 : 0) + ...);
    
    template <template <typename...> class C, typename ... Ts>
    struct my_predicate
     {
       template <typename ... Us>
       using my_is_same = C<Ts..., Us...>;
     };
    
    template <typename T, typename... Ts>
    void foo(T)
       requires (count_if<my_predicate<std::is_same, T>::template my_is_same, Ts...> == 1)
     { }
    

    【讨论】:

    • 我不知道这是可能的,谢谢。但是,这可能以更一般的方式吗?像template &lt;template &lt;typename...&gt; typename predicate, typename... Ts&gt; 这样的东西可以支持谓词的可变大小模板列表吗?您必须根据谓词采用多少个参数来拆分参数包Ts......我不知道这是否可能。
    • @user3520616 - 您可以用更一般的方式为谓词编写template &lt;template&lt;typename...&gt; typename predicate。但是你必须写计数器来喂它;也许是其他人......但我没有看到以一般方式喂养predicate的方法。
    • @user3520616 - 答案改进;希望这会有所帮助。
    • 感谢您分享的其他代码对我很有帮助!
    • @user3520616 - 答案再次得到改进(增加了灵活性)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-24
    相关资源
    最近更新 更多