【问题标题】:Passing a concept to a function将概念传递给函数
【发布时间】:2020-03-11 12:52:16
【问题描述】:

由于概念被定义为编译时谓词,是否也可以将这些谓词实际重用于编译时算法?例如,是否可以检查元组中的所有类型是否都符合一个概念?据我所知,不可能以任何方式将概念传递给函数,这让我回到了在这些情况下使用模板。

#include <type_traits>

template<typename T>
concept FloatLike = std::is_same_v<T, float>;

struct IsFloat
{
    template<typename U>
    constexpr static bool test()
    {
       return FloatLike<U>;
    }
};


template<typename Predicate, typename... T>
constexpr bool all_types()
{
    return (Predicate::template test<T>() && ...);
}


int main()
{
   static_assert(all_types<IsFloat, float, float>());
   static_assert(!all_types<IsFloat, float, int>());
}

我想做的是这样的事情,所以我不必一直包装这个概念就可以使用它:

template<concept Predicate, typename... T>
constexpr bool all_types()
{
    return (Predicate<T> && ...);
}


int main()
{
   static_assert(all_types<FloatLike, float, float>());
   static_assert(!all_types<FloatLike, float, int>());
}

有没有办法接近这个?

【问题讨论】:

  • 然后会有增加概念概念的提议...顺便说一句,all_types()可以使用折叠表达式大大简化... &amp;&amp;:return (... &amp;&amp; Predicate::template test&lt;Ts&gt;());
  • @Evg 会很棒 :)

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


【解决方案1】:

如果你的目标是“检查一个元组中的所有类型是否符合一个概念”,那么你可以这样做:

// concept to check if all types in Ts are the same as T
template<typename T, typename... Ts>
concept AllSame = (std::is_same_v<T,Ts> && ...);

// function only accepts floats as template parameters
template<AllSame<float>... Floats>
constexpr void float_foo()
{
}

// function only accepts ints as template parameters
template<AllSame<int>... Ints>
constexpr void int_foo()
{
}

// function only accepts T as template parameters
template<typename T, AllSame<T>... Ts>
constexpr void foo()
{
}

int main()
{
    int_foo<int, int, int>();
    // int_foo<int, int, double>(); // fails to compile
    float_foo<float, float, float>();
    // float_foo<float, float, int>(); // fails to compile
    foo<int, int, int, int>();
    // foo<int, int, int, float>(); // fails to compile
    foo<double, double, double, double>();
    // foo<double, double, double, int>(); // fails to compile

}

LIVE DEMO

【讨论】:

  • 为什么你的AllSame 是可变参数? type-constraint 引入的包中的每个模板参数都已单独受到约束。
  • @DavisHerring 我不明白。你是指概念本身还是*_foo()中的模板参数?
  • 我的意思是,如果你删除 Ts 上的 ... 和使用它的 &amp;&amp; ...,你的代码就可以工作。 (显然AllSame 这个名字不合适,但我不知道为什么我要把一元计数表示为&lt;int,int,int&gt;。)
  • 显然是std::same_as。我不认为可变参数部分是重点:它是概念的(期望的)变量identity。我的观点是,您的概念示例的可变参数方面与其使用无关(因为非可变参数概念已经与模板参数包一起使用)。
【解决方案2】:

有没有办法接近这个?

嗯,不,不是真的。不在 C++20 中。今天的语言中没有模板概念参数的概念。甚至变量模板也不能用作模板参数。所以如果有一个概念开始,我们就不能避免包装。

但我们可以做的是编写更简单的包装器。如果我们同意使用“旧式”类型特征作为谓词,特别是那些行为类似于 std::integral_constants 的特征,那么我们可以拥有可以用作谓词的非常简洁的“概念”定义。

template<typename T>
using FloatLike = std::is_same<T, float>;

template<template <typename> class Predicate, typename... T>
constexpr bool all_types()
{
    return (Predicate<T>{} && ...);
}

就我所见,它和it can get 一样好。

【讨论】:

  • 是否可以通过以任何方式将通用 lambda 类型化为模板模板来实现?似乎 lambda 从来都不是模板,虽然对,只有调用运算符?
  • @AndreasLoanjoe - 确实。 lambda 永远不是模板。但是,如果您愿意传递 lambda,那么 C++20 允许您这样做。我可以在几分钟内添加一个变体。
  • @AndreasLoanjoe - 再三考虑,lambda 仍然非常冗长。我不认为这是一个很好的选择。无论如何godbolt.org/z/QSHy8X
  • 我希望他们能添加一些更好的东西 :),但是看起来这就是答案,只有样式类型特征确实提供了这个功能概念(还没有)。
猜你喜欢
  • 2021-10-05
  • 1970-01-01
  • 2019-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-28
  • 2020-01-12
  • 2012-11-18
相关资源
最近更新 更多