Передача поняття функції


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

Чи є якийсь спосіб наблизитися до цього?


І тоді буде пропозиція додати концепції понять ... До речі, all_types()можна значно спростити , використовуючи кратні вираження ... &&:return (... && Predicate::template test<Ts>());
EVG

@Evg це було б чудово :)
Ігор Р.

Відповіді:


5

Чи є якийсь спосіб наблизитися до цього?

Ну ні, не дуже. Не в С ++ 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>{} && ...);
}

Наскільки це добре , наскільки я можу бачити.


Чи вдасться це зробити, декларувавши загальну лямбда як шаблон шаблону? Здається, лямбда ніколи не є шаблоном, хоча правильно, лише оператор виклику?
Andreas Loanjoe

@AndreasLoanjoe - Дійсно. Лямбда ніколи не є шаблоном. Але якщо ви готові передати лямбда навколо, тоді C ++ 20 дозволяє вам це зробити. Я можу додати варіант цього за кілька хвилин.
StoryTeller - Невідповідна Моніка

@AndreasLoanjoe - По другій думці, лямбда все ж виходить дуже багатослівним. Я не думаю, що це чудова альтернатива. Ось так чи інакше godbolt.org/z/QSHy8X
StoryTeller - Невідповідна Моніка

Я сподіваюся, що вони додадуть щось краще :), але так, здається, це відповідь, але тільки риси типу стилю пропонують цю функціональну концепцію (поки що).
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

}

LIVE DEMO


Чому ваш AllSameваріант? Кожен параметр шаблону в пакеті, що вводиться обмеженням типу, вже обмежений окремо.
Девіс Оселедець

@DavisHerring Я не розумію. Ви маєте на увазі саме поняття або параметри шаблону *_foo()?
kanstar

Я маю на увазі, що код, який у вас є, працює, якщо ви вилучите ...ввімкнути Tsі той, && ...хто його використовує. (Очевидно, що ім'я AllSameтоді було б невідповідним, але я не впевнений, чому я б хотів висловити кількість унарних як <int,int,int>інакше.)
Девіс Херінг

@DavisHerring Тоді ця концепція не була б, AllSameале SameAs(див. En.cppreference.com/w/cpp/concepts/same_as ) і ОП хотів мати концепцію, яка приймає різну кількість параметрів шаблону.
kanstar

Очевидно, що було б std::same_as. Я не думаю, що в різній частині була суть: це була (бажана) змінна ідентичність концепції. І моя думка полягала в тому, що варіатичний аспект прикладу вашого поняття не має значення для його використання (адже неріадактичні концепції вже працюють із пакетами параметрів шаблону).
Оселедець Девіса
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.