2

I am very unclear when to use non-type template arguments (C++20) or normal arguments in constexpr functions. It's unclear to me, what the restrictions are and when to switch from pure parameters to non-type template parameters (see Live). Here an example which illustrates the clunkiness with normal arguments:

template<typename Tuple, typename Pred>
constexpr auto getLambda(Tuple&& tuple, Pred&& pred)
{
   return [=](auto I, auto J) {
        return pred(std::get<I>(tuple), std::get<J>(tuple));
   };
}

template<typename T>
struct A
{
    constexpr A(T t) : val(t){};
    T val;
};

int main()
{
    static constexpr auto t = std::make_tuple(A{10.0}, A{1});
    constexpr auto p   = [](auto&& a, auto&& b) { return a.val < b.val; };
    constexpr auto s   = getLambda(t, p);
    //constexpr auto b = s(1,0); // that does unfortunately not compile -> go back write differently... :-|||
}

Mostly I first try to use normal arguments like above, and after cumbersome fiddling with compile errors about non-constant expressions, try an approach with template<auto t> (non-type template paramters. Mostly having then two implementations one for each use-case (this seems stupid to me...)

Its sounds to me that modern generic programming with C++20 tends towards compile-time computations using constexpr together with some type-meta-programming. Could anyone shed some light into this rather new "dark-corner" of C++. I probably misunderstand when something is not a constant-expression and when it is...

Gabriel
  • 8,990
  • 6
  • 57
  • 101
  • 1
    A function parameter is never `constexpr`, only possibly the value returned from the function. A `constexpr` function must be callable both at compile-time and run-time. Hence `I` and `J` are not usable in `std::get`. – super Jan 04 '20 at 01:56
  • 1
    But you might do `constexpr auto b = s(std::integral_constant{}, std::integral_constant{});` [Demo](http://coliru.stacked-crooked.com/a/0a7ecef7647ede15) – Jarod42 Jan 04 '20 at 07:19
  • @super Why can I then call `getLambda(t,p)`, doesnt evaluating a `constexpr` directly need the argument also a `constant expression` which `t` and `p` are, so `tuple,pred` are constant-expressions ?. Is `constexpr auto s` only a guide that `auto s` might be computed at compile-time, but here it isnt... ? – Gabriel Jan 04 '20 at 10:58
  • 1
    @Gabriel `t` and `p` are `constexpr` and guaranteed so. But once you enter the function body of `getLambda`, then `tuple` and `pred` are **not** constant expressions, even if the parameter passed were. Same thing applies to `1/0` and `I/J`. – super Jan 04 '20 at 11:26
  • Maybe [this paper](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0992r0.pdf) will help clarify things more for you. – super Jan 04 '20 at 11:46
  • Does this answer your question? [Will consteval functions allow template parameters dependent on function arguments?](https://stackoverflow.com/questions/56130792/will-consteval-functions-allow-template-parameters-dependent-on-function-argumen) – Davis Herring Jan 04 '20 at 14:40

1 Answers1

2

The short version: Use non-type template parameter to set non-type template arguments (more general everywhere, where you need a constant expression) and normal arguments for everything else.

The thing about constexpr functions you always have to keep in mind is that they can also be called at runtime. So every normal argument is not necessarily a constant expression. Hence you cannot use it to provide a non-type template argument (as the I in std::get<I>).

Of course one could argue that when called to calculate a constexpr variable the passed arguments are always constant expressions and could be used as such also inside the function. But it would be unexpected if a constexpr function works at compile time but not anymore at runtime.

One could expect that with the new consteval keyword in C++20, one could use normal arguments to consteval functions in constant expressions, since we know that these arguments have to be constant expressions. But this does not seem to be the case: https://godbolt.org/z/guz7FQ Why this is the case I do not know. But in general I like the seperation between normal variables and non-type template arguments.

n314159
  • 4,990
  • 1
  • 5
  • 20
  • Some more details on `consteval` and why it's parameters are not usable in constant expressions can be found [here](https://stackoverflow.com/questions/57226797/will-consteval-allow-using-static-assert-on-function-arguments). – super Jan 04 '20 at 11:30