Martin Kopecký - 10 months ago 51

C++ Question

I would like to ask you for help with the programming headache I face last few days. Let me try to explain what I am about to implement...

My goal is to define a set of equations with its validity. Let me explain more in detail...

I think about being each equation object a functor - a class defining the

`operator()`

.h:

`enum class IDs : int { A = 0, B = 1, C = 2 };`

template<IDs WHICH>

struct Equation

{

int operator() ( void );

}

.cpp:

`template<>`

Equation<IDs::A>::operator()( void )

{

/* Just some sample equation */

return( 42 + 28 );

}

As you may have noticed, the specialization is defined by enum class member IDs::?.

This seems to be working. But I would like to add so called availability feature - The equation may be valid only for certain user object types.

`There is 'validity group' declared:`

/* Object types declaration */

namespace Objects {

using Object0 = boost::mpl::int_<0>;

using Object1 = boost::mpl::int_<1>;

using Object2 = boost::mpl::int_<2>;

}

/* Validity groups declaration */

using ValidityGroup1 = boost::mpl::vector<Object0, Object2>;

using ValidityGroup2 = boost::mpl::vector<Object1>;

I am using the following construct to make the class enabled or disabled (using boost::enable_if). Just to show how I use it:

`template<typename TYPE_LIST, typename QUERY_TYPE>`

struct IsTypeInList

{

using TypePos = typename boost::mpl::find<TYPE_LIST, QUERY_TYPE>::type;

using Finish = typename boost::mpl::end<TYPE_LIST>::type;

using type = typename boost::mpl::not_<boost::is_same<TypePos, Finish> >::type;

using value_type = typename type::value_type;

static const bool value = type::value;

};

template<typename OBJECT_TYPE, typename ENABLER=void>

class SampleClass;

template<typename OBJECT_TYPE>

class SampleClass<OBJECT_TYPE, typename boost::enable_if<typename IsTypeInList<ValidityGroup1, Object0>::type>::type>

{}

The partial specialization of SampleClass is available only if

`Object0`

`ValidityGroup1`

Now the funny stuff comes. I would like to merge the two things together:

I know the whole concept is quite complicated and may be confusing. Let me show my attempt to implement this stuff:

`template<typename OBJECT_TYPE, typename VALIDITY_GROUP, IDs ID, typename ENABLER = void>`

class Equation;

template<typename OBJECT_TYPE, typename VALIDITY_GROUP, IDs ID>

class Equation<OBJECT_TYPE, VALIDITY_GROUP, ID, typename boost::enable_if<typename IsTypeInList<VALIDITY_GROUP, OBJECT_TYPE>::type>::type >

: public EquationBase<IDs>

{

public:

int operator() ( void );

};

template<typename OBJECT_TYPE, typename VALIDITY_GROUP, IDs ID>

int Equation<OBJECT_TYPE, ValidityGroup1, Ids::A>::operator() ( void )

{

return( 42 + 56 );

}

But the operator() definition is not working... Could you please advise me how to make this working? Or does anyone have any other idea how to fulfill the goal written above?

Cheers Martin

The equation is used in template class object. Let the code explain:

`template<typename OBJECT_TYPE>`

class Object

{

public:

Object( void );

};

.cpp:

`template<typename OBJECT_TYPE>`

Object<OBJECT_TYPE>::Object( void )

{

std::cout << Equation<IDs::A>()() << std::endl;

}

The problem is OBJECT_TYPE is not defined when the operators () are specialized...

Answer Source

If I understand correctly what you want to obtain, I suppose there are many ways.

The following is a iper-semplified example (but complete ad working) that show how to select different implementations using `std::enable_if`

(but `boost::enable_if`

should be OK) with the return type of the operator

```
#include <iostream>
#include <type_traits>
template <typename ObjT, typename ValT>
class Equation
{
public:
template <typename X = ObjT>
typename std::enable_if<true == std::is_same<X, ValT>::value, int>::type
operator() ( void )
{ return( 0 ); }
template <typename X = ObjT>
typename std::enable_if<false == std::is_same<X, ValT>::value, int>::type
operator() ( void )
{ return( 1 ); }
};
int main()
{
Equation<int, int> eq0;
Equation<int, long> eq1;
std::cout << "eq0 val: " << eq0() << std::endl; // print "eq0 val: 0"
std::cout << "eq1 val: " << eq1() << std::endl; // print "eq1 val: 1"
}
```

Not really elegant, I suppose.

Another solution (that, I suppose, best fits your desiderata) could be the following based on class partial specialization

```
#include <iostream>
#include <type_traits>
template <typename ObjT, typename ValT, bool = std::is_same<ObjT, ValT>::value>
class Equation;
template <typename ObjT, typename ValT>
class Equation<ObjT, ValT, true>
{
public:
int operator() ();
};
template <typename ObjT, typename ValT>
class Equation<ObjT, ValT, false>
{
public:
int operator() ();
};
template <typename ObjT, typename ValT>
int Equation<ObjT, ValT, true>::operator() ()
{ return( 0 ); }
template <typename ObjT, typename ValT>
int Equation<ObjT, ValT, false>::operator() ()
{ return( 1 ); }
int main()
{
Equation<int, int> eq0;
Equation<int, long> eq1;
std::cout << "eq0 val: " << eq0() << std::endl; // print "eq0 val: 0"
std::cout << "eq1 val: " << eq1() << std::endl; // print "eq1 val: 1"
}
```