Reputation: 6255
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
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
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
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