Let's say we have a consteval
function or a trivial struct with consteval
construnctor, which only accept some of the values:
struct A
{
consteval A(int a)
{
// compile error if a < 0
if (a < 0)
throw "error";
}
};
Is there any way to detect if a non-type template parameter of int could be accepted by such a constructor? I have tried the following code but failed.
template <int a> concept accepted_by_A = requires() {A(a);};
int main()
{
std::cout << accepted_by_A<-1> << std::endl; // output 1 (true)
}
CodePudding user response:
Since a call to a constexpr
(or consteval
) function that throws is not a constant expression, you can detect this:
template<int I> concept accepted_by_A=
requires() {typename std::type_identity_t<int[(A(I),1)]>;};
static_assert(accepted_by_A<1>);
static_assert(!accepted_by_A<-1>);
It's also possible to use SFINAE (which would allow it to work with constexpr
in previous language versions):
template<int,class=void> struct test : std::false_type {};
template<int I> struct test<I,decltype(void((int(*)[(A(I),1)])nullptr))> : std::true_type {};
static_assert(test<1>());
static_assert(!test<-1>());
An alternate specialization
template<int I> struct test<I,typename voided<int[(A(I),1)]>::type> : std::true_type {};
seems like it ought to work but doesn't; substitution of non-type template arguments is weird in some cases.