Home > Back-end >  While template deduction, is it possible to detect if a consteval function could be run
While template deduction, is it possible to detect if a consteval function could be run

Time:12-16

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.

  • Related