0

I'm trying to make a simple way to generate std::array's at compile time. It's been a struggle so far to figure out a good way to pass a constexpr function in at compile time. The workaround I have found so far is like this.

#include <iostream> #include <array> namespace a { constexpr int f(const int & i) { return i * i * i;} #include "generate_with_function.hpp" } int main() { auto arr = a::generator<false,10,0>::array; for (auto i : arr) { std::cout << i << " "; } return 0; } 

this basically assumes you will define a function called f and I wrapped it in a namespace incase I wanted to do a different one. I wanted to know if there is a more clever way to pass in the function and use it at compile time. Also here is the code that makes the list.

template <bool B, size_t Count,int ... Nums> struct generator; template <size_t Count> struct generator<false,Count,0> { constexpr static std::array<int,Count> array = generator<false,Count,1,f(0)>::array; }; template <size_t Count, int Current, int ... Results> struct generator<false,Count,Current, Results...> { constexpr static std::array<int,Count> array = generator<Current+1==Count,Count,Current+1,f(Current), Results...>::array; }; template <size_t Count, int Current, int ... Results> struct generator<true,Count,Current,Results...> { constexpr static std::array<int,Count> array{{Results...}}; }; 

and before you ask no I don't actually have a real need for this.

As noted by @us2012 I should be specific about what I would rather have.

  1. nowrapping in namespace
  2. having to write the function but not actually passing it anywhere
  3. and not requiring the function to be named f
6
  • When you say "a more clever way", which particular property of your current solution are you trying to avoid? Commented Oct 10, 2013 at 1:05
  • @us2012 couple things, wrapping in namespace, having to write the function but not actually passing it anywhere and requiring the function to be named f Commented Oct 10, 2013 at 1:06
  • The namespace doesn't seem to be necessary Commented Oct 10, 2013 at 1:13
  • @sth if you want to reuse it with a different function it is Commented Oct 10, 2013 at 1:15
  • 1
    Btw, here's my solution to that problem. It does pass the function (as a pointer), though. Commented Oct 10, 2013 at 6:16

1 Answer 1

2

You can actually use the function as a template parameter, here called Gen:

template <bool B, size_t Count, int Current, int Gen(size_t), int ... Nums> struct generator; template <size_t Count, int Current, int Gen(size_t), int ... Results> struct generator<false,Count,Current, Gen, Results...> { constexpr static std::array<int,Count> array generator<Current+1==Count,Count,Current+1,Gen, Gen(Current), Results...>::array; }; template <size_t Count, int Current, int Gen(size_t), int ... Results> struct generator<true,Count,Current,Gen,Results...> { constexpr static std::array<int,Count> array{{Results...}}; }; 

With this it actually works to pass a constexpr function to the template (if the type matches exactly):

// helper to hide the "internal" template parameters template <size_t Count, int Gen(size_t)> struct gen { constexpr static std::array<int, Count> array = generator<false, Count, 0, Gen>::array; }; constexpr int f(size_t i) { return i * i * i; } int main() { auto arr = gen<10,f>::array; for (auto i : arr) { std::cout << i << " "; } return 0; } 

You can also switch around the Gen(Current) and Results... parameters to get the values at the "correct" array indexes.

Sign up to request clarification or add additional context in comments.

6 Comments

This looks like it might work, the function takes an int though
@aaronman: Like written here it only works if the function takes size_t, but it could probably be generalized by adding even another template parameter for the parameter type of the function, or so.
I just meant because the one I wrote uses int
Thanks, my problem from before is that I thought a function was not allowed to be a non-type template param
@aaronman A function type is not allowed as type of a non-type template parameter, but a function type decays to a pointer-to-function type (even) in template parameters. And pointer-to-function (as well as reference to function) is allowed as type for a non-type template parameter. Additionally, integral, enumeration, lvalue reference, pointer-to-object, pointer-to-member and nullptr_t are allowed as types [temp.param]/4.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.