atomgalaxy / isocpp-universal-template-param

We propose a way to spell a universal template parameter kind. This would allow for a generic apply and other higher-order template metafunctions, and certain typetraits.
https://atomgalaxy.github.io/isocpp-universal-template-param/d1985r0.pdf
2 stars 2 forks source link

Allow by value function template template parameters. #51

Open BengtGustafsson opened 1 year ago

BengtGustafsson commented 1 year ago

Currently a function (by value) can be a template parameter:

template<int(f)(int)> struct X {
    int callf() { return f(1); }
}; 

This is logical as template parameters are constexpr, so there is no need for a reference or pointer. Thus, for consistency, a function template template parameter, which is a subset of variable template template parameters should be allowed to be by value:

template<template<int A> int(f)(int)> struct Y {
    int callf() { return f<1>(2); }
};

This is in contrast with template variables of function type, which must be references or pointers to the actual function:

template<int B> int tfun(int a) { return a + B; }   // function template

template<int A> int(*ftpl)(int) = tfun<A>;          // variable template of function pointer type.

Here the template variable ftpl has to have pointer or reference type (even if it is const or even constexpr). For consistency with non-template functions template parameters (as in the first snippet above) by value functions should be allowed as function template template parameters. This should be clear in the wording.

camaclean commented 1 year ago

I think this goes beyond what we should tackle in this paper. struct X has an NTTP parameter. It just has a function type. As a templated parameter, it would be a variable template, and those have to be auto for reasons we discussed in the paper.

template<template<int> auto f> struct Z {};

struct Y is trying to constrain the type of variable template.

We could have a separate paper to enhance functions as variable templates. For instance, we could make it so that variable templates can be used to express an overload set:

template<typename R, typename... Args>
constexpr R(func)(Args...) = &funcname; //make it so that funcname can be undefined here and delay failure till substitution.

That variable template could then be passed as a variable template argument where SFINAE/requires can be used to check for the existence of an overload. Template deduction as a function would also be made to apply. I'm not sure what the syntax for specifying a templated function would be, but these are just initial ideas at the moment.

At any rate, functions are just NTTPs at the moment and aren't special. We could do cool things in handling them specially as a way to specify overload sets, but that's orthogonal to p1985. We should consider it, but we need to put thought into how exactly such handling should work.