InsideLoop
InsideLoop

Reputation: 6255

Template parameters simplification

I am fairly new to C++ (using C++ 2011) and I would like to find a solution for the following problem. I have a class that represents a fonction:

class Curve {
private:
    ...
public:
    std::array<double, 3> value(double s);
}

I am using that object to pass this function to an algorithm that is represented by a class:

template <int n, typename Functor>
class Algorithm {
private:
    Functor f;
    std::array<double, n> a;
public:
    ...
}

Then I create the object

Algorithm<3, Curve> solver;

But the 3 is obviously the 3 coming from the size of the array returned by the method value of any objet of type Curve. I would like to simplify this code so that I can use :

Algorithm<Curve> solver;

But I have no idea on how to do that. Would you mind giving me a hint ?

Best regards, Francois

Upvotes: 4

Views: 124

Answers (3)

wonko realtime
wonko realtime

Reputation: 565

You could "pass" the 3 in an enum member like this:

class Curve {
public:
   enum { arity = 3 };
   std::array<double, arity> value(double s);
};

template <typename Functor>
class Algorithm {
private:
   std::array<double, Functor::arity> a;
};

Curve curve;
Algorithm<Curve> solver;

Upvotes: 1

Casey
Casey

Reputation: 42554

Use decltype to get the return type of value, and std::tuple_size to find out how big it is (Live at Coliru):

template <typename Functor>
class Algorithm {
private:
    Functor f;
    static const std::size_t n =
      std::tuple_size<decltype(f.value(0.))>::value;
    std::array<double, n> a;
public:
    // ...
};

or if you simply want a to have the same type that value returns:

template <typename Functor>
class Algorithm {
private:
    Functor f;
    decltype(f.value(0.)) a;
public:
    // ...
};

or if you might someday want to use functions of a different type - say int or long long or whatever - you can ask for the return type of f.value when invoked with a default-constructed value of whatever its argument type happens to be:

template <typename Functor>
class Algorithm {
private:
    Functor f;
    decltype(f.value({})) a;
public:
    // ...
};

Upvotes: 1

Manu343726
Manu343726

Reputation: 14174

Add a member array_length or something similar to the Curve like classes:

class Curve
{
public:
    static constexpr const std::size_t length = 3;

private:
    std::array<double,length> a;
};

template<typename ALGORITHM , std::size_t n = ALGORITHM::length>
class Algorithm
{
    ...
};

If you need to allow classic function entities as algorithms, that approach doesn't work since there is no length member. Other way could be to create a metafunction data_length which given a algorithm function F returns the length of the data:

template<typename F>
struct length;

//Specialization for Curve class:
template<>
struct length<Curve> : public std::integral_constant<std::size_t,3>
{};

And then:

template<typename F , std::size_t n = length<F>::value>
struct Algorithm
{
   ...
};

EDIT: Like in any other template, to implement the method specify its template parameters:

template<typename F , std::size_t N>
void Algorithm<F,N>::execute()
{
    _f();
}

Here is a running example.

Upvotes: 8

Related Questions