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

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

本文关键字:类型 参数 函数 属性 调用      更新时间:2023-10-16

假设您有一个名为Funcenum class、一个具有Func属性的类和一个包含函数模板compute:的Functions

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属性来实现此功能?

模板解析是一种完全编译时机制。在这种情况下,您需要在运行时选择调用哪个函数:函数指针、虚拟函数、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.
}
};

使用模板无法解决此问题。模板解析附加和编译时,并且您希望选择运行时。有很多解决方案,比如提出的解决方案,但没有一个能够利用模板。