2

I have the following code which compiles nicely:

#include <iostream>

struct Res {};
struct Jac {};

template <typename T, typename S>
class A;

template <typename S>
class A<Res, S>
{
    public:
        A() { std::cout << "A<Res, S>" << std::endl; }
};

template <typename S>
class A<Jac, S>
{
    public:
        A() { std::cout << "A<Jac, S>" << std::endl; }
};



template <typename T, typename S>
class B;

template <typename S>
class B<Res, S>
{
    public:
        B() { std::cout << "B<Res, S>" << std::endl; }
};

template <typename S>
class B<Jac, S>
{
    public:
        B() { std::cout << "B<Jac, S>" << std::endl; }
};


template<typename S, typename EvalT,
    std::enable_if_t<std::is_same<EvalT, A<Res,S>>::value, bool> = true
>
void foo() 
{
    A<Res, S> a_res;
    A<Jac, S> a_jac;
}

template<typename S, typename EvalT,
    std::enable_if_t<std::is_same<EvalT, B<Res,S>>::value, bool> = true
>
void foo()
{
    B<Res, S> b_res;
    B<Jac, S> b_jac;
}

int main() {

    foo<int, A<Res,int>>();
    foo<int, B<Res,int>>();

    return 0;
}

However I am not happy with the calls inside my main() function. I would like them to look like this:

    foo<int, A>();
    foo<int, B>();

which would imply the following modification of the templates for foo():

template<typename S, typename EvalT,
    std::enable_if_t<std::is_same<EvalT, B>::value, bool> = true
>
void foo()
{
    B<Res, S> b_res;
    B<Jac, S> b_jac;
}

This obviously does not compile. The idea is to have a function, which would instantiate either A or B without explicitly specifying T for my classes because I know that foo() has to create 2 instances with Res and Jac as type parameters. Is there any way to make the code neater and achieve such a behavior?

1 Answers1

1

You can change foo to accept a template template parameter CT that is templated on two types, and enable_if the specific overload based on whether CT<Res, S> is the same type as A<Res, S>, or B<Res, S>:

template<typename S, template<typename, typename> typename CT,
    std::enable_if_t<std::is_same<CT<Res,S>, A<Res,S>>::value, bool> = true
>
void foo() 
{
    A<Res, S> a_res;
    A<Jac, S> a_jac;
}

template<typename S, template<typename, typename> typename CT,
    std::enable_if_t<std::is_same<CT<Res, S>, B<Res,S>>::value, bool> = true
>
void foo()
{
    B<Res, S> b_res;
    B<Jac, S> b_jac;
}

Here's a demo.

cigien
  • 57,834
  • 11
  • 73
  • 112