将概念传递给功能


12

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

#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>());
}

有什么办法可以做到这一点?


然后会有一个建议来添加概念的概念... BTW,all_types()可以使用折叠表达式大大简化... &&return (... && Predicate::template test<Ts>());
Evg

@Evg太好了:)
Igor

Answers:


5

有什么办法可以做到这一点?

好吧,不,不是真的。不在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>{} && ...);
}

它的好,因为它可以得到,只要我能看到。


通过以某种方式将通用lambda删除为模板模板是否可以工作?似乎lambda永远不是模板,虽然正确,只有调用运算符?
安德烈亚斯(Andreas Loanjoe)

@AndreasLoanjoe-的确如此。Lambda绝不是模板。但是,如果您愿意传递lambda,则C ++ 20允许您这样做。我可以在几分钟内添加一个变体。
StoryTeller-Unslander Monica,

@AndreasLoanjoe-再想一想,lambda仍然非常冗长。我认为这不是一个很好的选择。无论如何,这里是godbolt.org/z/QSHy8X
StoryTeller-Unslander Monica,

我希望他们会添加一些更好的东西:),但是是的,这似乎是答案,只有样式类型特征确实提供了此功能概念(尚未)。
Andreas Loanjoe,

0

如果您的目标是“检查元组中的所有类型是否都符合概念”,则可以执行以下操作:

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

}

现场演示


为什么您的AllSame可变参数?由类型约束引入的包中的每个模板参数已经分别受到约束。
戴维斯·鲱鱼

@DavisHerring我不明白。您是指概念本身还是其中的模板参数*_foo()
kanstar

我的意思是,如果删除...on Ts及其&& ...使用它的代码,那么您拥有的代码将起作用。(显然,这个名字AllSame不恰当,但是我不确定为什么我还是想用一元表示一个数<int,int,int>。)
Davis Herring

@DavisHerring然后这个概念不会是AllSame,但SameAs(见en.cppreference.com/w/cpp/concepts/same_as)和OP想有一个概念,这需要的模板参数的可变参数数量。
kanstar

显然是这样std::same_as。我不认为可变参数部分是关键:这是概念的(所需)变量标识。我的观点是,您的概念示例的可变参数部分与它的使用无关(因为非可变概念已经可以与模板参数包一起使用)。
戴维斯·鲱鱼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.