3

I have a class template Foo which has several members, one of which is a function bar of type Bar:

template<std::size_t N>
class Foo
{
    ...
    Bar<N> bar;
    ...
};

I would like Bar<2> to be a template alias for a function double (* )(double, double) (or possibly std::function<double(double, double)>). Similarly, I want Bar<3> to be a template alias for a function double (* )(double, double, double) (or possibly std::function<double(double, double, double)>). This means that N should specify the number of double arguments that the function bar takes.

The only way I managed to get anywhere close to this behaviour, is by using the template alias

template <std::size_t N>
using Bar = double (* )(std::array<double, N>& eval);

In this way, however, I can not call the function bar in its natural way bar(x,y,z).

Is it possible to get the behaviour that I want?

2 Answers 2

4

With extra layer, you might do:

template <typename T>
struct BarHelper;

template <std::size_t ... Is>
struct BarHelper<std::index_sequence<Is...>>
{
private:
    template <std::size_t, typename T>
    using always_t = T;
public:
    using type = double (*) (always_t<Is, double>...);
};

template <std::size_t N>
using Bar = typename BarHelper<std::make_index_sequence<N>>::type;

std::index_sequence is C++14, but can be implemented in C++11.

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

3 Comments

I will have to figure out what std::index_sequence does exactly, but this works like a charm! While trying some thins out with this code, I noticed that it also works with lambda expressions (although only without captures). It also does not seem to work with std::function<double(double, double)>. Do you know the reason for this, and perhaps a way to get it to work with that as well?
std::make_index_sequence<N> is an alias to std::index_sequence<0, 1, .., N-1>. so a way to have a collection of number at compile time to ease "iteration".
Lambda [](double)->double can indeed be converted to double (*) (double), but not capturing lambda or std::function. You might change using type = double (*) (always_t<Is, double>...); by using type = std::function<double(always_t<Is, double>...); if you want to support that.
1

An other option, without index_sequence:

template<class T> 
struct add_double_arg;

template<class R,class...Args>
struct add_double_arg<R(Args...)>{
    using type = R(Args...,double);
};

template<int N,template<class> class Transform,class Init>
struct repeat{
    using type = typename Transform<
           typename repeat<N-1,Transform,Init>::type
                  >::type;
};
template<template<class> class Transform,class Init>
struct repeat<0,Transform,Init>{
    using type = Init;
};

template<int N>
using Bar = typename repeat<N,add_double_arg,double()>::type *;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.