使用 class 属性调用带有非类型模板参数的模板函数

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

假设您有一个名为 Funcenum class,一个具有 Func 属性的 class 和一个包含函数的 Functions class模板 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.
        }
}

我想通过传递 func 属性从 Functions 调用适当的专用模板。但是,这不起作用,因为 func 在编译时未知。我在 clang 中收到以下错误:

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

我相信我可以通过将 Foo 中的 compute 方法也作为模板并专门针对每个 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.

然而,这违背了目的,因为我想在 Foo 中使用 func 属性。另外,我想避免双重处理,因为 Foo::compute() 执行更多操作,我必须将这些操作复制到每个专业化中。

有没有办法通过使用 func 属性来实现这个功能?

模板解析是一种完全编译时的机制。在这种情况下,您需要一些方法 select 在运行时调用哪个函数:函数指针、虚函数、switch 语句...

使用函数指针的示例:

typedef double (*Func)(const std::vector<double>&);

double Sin(const std::vector<double>& args) {
    return std::sin(args[0]);
}
// etc.

class Foo
{
    private:

        Func func;
        double result;

    public:

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

您不必专精 Foo::compute。您可以直接使用您的通用定义:

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

如果你想把你的运行时成员变成编译时值,你必须自己调度。 switch 或数组都是可能的方式

class Foo
{
private:

    Func func;
    double result;

public:

    void compute(const std::vector<double>& _args)
    {
        switch (func) {
        case Func::Sin: result = Functions::compute<Func::Sin>(_args); break;
        case Func::Cos: result = Functions::compute<Func::Cos>(_args); break;
        // ...
        }
        // A few other operations follow.
    }
};

您无法使用模板解决此问题。模板解析附加和编译时间,你想选择一个 运行 时间。 有很多解决方案,例如所提出的解决方案,但其中 none 将使用模板。