개념은 컴파일 타임 술어로 정의되므로 실제로 컴파일 타임 알고리즘에 이러한 술어를 재사용 할 수 있습니까? 예를 들어 튜플의 모든 유형이 개념을 준수하는지 확인할 수 있습니까? 내가 본 한, 어떤 식 으로든 개념을 함수에 전달하는 것은 불가능합니다.이 경우 이러한 경우에 템플릿을 사용하게됩니다.
#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>());
}
이것에 더 가까이 갈 수있는 방법이 있습니까?
답변
이것에 더 가까이 갈 수있는 방법이 있습니까?
아뇨 C ++ 20에는 없습니다. 오늘날 템플릿 개념 매개 변수에 대한 개념은 없습니다. 변수 템플릿도 템플릿 매개 변수로 사용할 수 없습니다. 따라서 시작하는 개념이 있으면 줄 바꿈을 피할 수 없습니다.
그러나 우리가 할 수있는 것은 더 간단한 래퍼를 작성하는 것입니다. “오래된 스타일”유형의 특성을 술어, 특히 std::integral_constant
s 처럼 행동하는 특성으로 사용하기로 동의하면 술어로 사용할 수있는 아주 “개념”정의를 가질 수 있습니다.
template<typename T>
using FloatLike = std::is_same<T, float>;
template<template <typename> class Predicate, typename... T>
constexpr bool all_types()
{
return (Predicate<T>{} && ...);
}
답변
목표가 “튜플의 모든 유형이 개념을 따르는 지 확인”하는 경우 다음과 같이 할 수 있습니다.
// 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
}