mercredi 2 août 2017

Calling template function with non-type template parameter using class attribute

Suppose you have an enum class called Func, a class with a Func attribute and a Functions class containing a function template compute:

enum class Func
{
    Sin,
    Cos
    // Others...
}

class Functions
{
    public:

        template<Func fn>
        static inline double compute(const std::vector<double>& _args);
}

template<>
inline double compute<Func::Sin>(const std::vector<double>& _args)
{
    return std::sin(std::accumulate(_args.begin(), _args.end(), 0.0));
}


template<>
inline double compute<Func::Cos>(const std::vector<double>& _args)
{
    return std::cos(std::accumulate(_args.begin(), _args.end(), 0.0));
}

// More specialisations...

class Foo
{
    private:

        Func func;
        double result;

    public:

        inline void compute(const std::vector<double>& _args)
        {
            result = Functions::compute<func>(_args);
            // A few other operations follow.
        }
}

I would like to call the appropriate specialised template from Functions by passing the func attribute. However, this doesn't work because func is not known at compile time. I get the following error in clang:

candidate template ignored: invalid explicitly-specified argument for template parameter 'fn'
                                       ^

I believe that I can achieve this by making the compute method in Foo a template as well and specialising for each Func:

class Foo
{
    private:

        Func func;
        double result;

    public:

        template<Func fn>       
        inline void compute(const std::vector<double>& _args)
        {
            result = Functions::compute<fn>(_args);
            // A few other operations follow.
        }
}

template<>
inline void compute<Func::Sin>()(const std::vector<double>& _args)
{
    result = Functions::compute<Func::Sin>(_args);
}

template<>
inline void compute<Func::Cos>()(const std::vector<double>& _args)
{
    result = Functions::compute<Func::Cos>(_args);
}

// Etc.

However, this defeats the purpose because I would like to use the func attribute in Foo. Also, I would like to avoid the double handling because Foo::compute() performs a few more operations, which I would have to copy into each specialisation.

Is there any way to achieve this functionality by using the func attribute?

Aucun commentaire:

Enregistrer un commentaire