Search code examples
c++templatesc++17autotemplate-argument-deduction

Use of auto in template parameters: Some usage examples and... how to make it work with constant size C arrays?


I have the following exemplary use of auto in template parameters (which I like independent of their sanity or existence of better alternatives, I am just trying to internalize the 'auto in template params' feature):

//1-Check if input is within open interval (l, h) where l & h are function parameters
//Example: int x = 5, y = fnc_y(), z = fnc_z(); auto fOk = gt_lt(z, x, y);
template<typename L, typename H, typename V> inline bool 
gt_lt(const V &v, const L& l, const H& h) { return (v > l) && (v < h); }

//2-Check if input is within open interval (l, h) where l & h are auto template parameters
//Example: int z = fnc_z(); auto fOk = gt_lt<5, 45>(z);
template<auto l, auto h, typename V>
inline bool gt_lt(const V &v) { return (v > l) && (v < h); }

//3-Fill a C array (a) of known size with a value where a is a function parameter: 
// char a[4]; fill_all(a, 'a');
template<typename TArrayValType, size_t N, typename TVal>
inline void fill_all(TArrayValType(&a)[N], const TVal &v) { std::fill(a, a + N, v); }

//4-Fill a C array (a) of known size with a value where a is an auto template parameter
//Can't figure out it!!! Goal: char a[4]; fill_all<a>('a');
template<auto a, **....what else to put it here?**, typename TVal>
inline void fill_all(const TVal &v) { std::fill(a, a + N, v); }

Usage No-4 does not work. How to make it work? I suspect something like in Extracting the value of SIZE without knowing its type would work but still can't make it work...

One motivation for uses such as above would be to avoid passing some values (when they are known at compile time) as function parameters even in debug mode for better debug performance, or hopefully sometimes benefit it from in fully-optimized builds in cases compile would generate even more efficient code if parameter passing is avoided thanks to auto for non-type parameters. But, yet, I am not still sure if that would make sense...


Solution

  • As far I know, you can't so simply.

    As you can read in this page

    Array and function types may be written in a template declaration, but they are automatically replaced by pointer to object and pointer to function as appropriate.

    So you can write

    template <auto a, typename TVal>
    inline void fill_all(const TVal &v)
     { }
    
    // ...
    
    static int a[4] {};
    
    fill_all<a>(2);
    

    but fill_all() see the type of a as a int *, not as int[4].

    So you can use it as pointer but you have lost the information about the dimension.

    The best I can imagine is call a constexpr function that return the size of the array and put this value as template parameter (or function argument)

    template <typename T, std::size_t N>
    constexpr std::size_t getDim (T const (&)[N])
     { return N; }
    
    template <auto a, std::size_t N, typename TVal>
    inline void fill_all (TVal const & v)
     { std::fill(a, a + N, v); }
    
    // ...
    
    static int a[4] {};
    
    fill_all<a, getDim(a)>(2);
    

    but, unfortunately, I don't see a way to avoid the explicit call of getDim() in the explicit template argument list.