gpt4 book ai didi

c++ - 使用多个参数包将运行时值转换为编译模板参数

转载 作者:行者123 更新时间:2023-11-30 05:27:42 24 4
gpt4 key购买 nike

在我第一次涉足可变参数模板时,我试图创建一个函数来实例化具有模板参数的所有组合的派生类。想法是让运行时选项类能够选择要使用的确切模板实例。我已经能够让基本案例使用 1 和 2 模板参数。但是一般情况下是行不通的,下面第三次调用 SelectInstance 编译失败,出现以下错误:

candidate function not viable: requires 3 arguments, but 2 were provided AbstractBase *SelectInstance(Func func, Args... args)

完整代码如下:

#include <memory>
#include <iostream>

struct Options
{
bool GetFirstParameter() { return true; }
bool GetSecondParameter() { return false; }
bool GetThirdParameter() { return true; }
};

struct AbstractBase
{
virtual void PrintMe() = 0;
};

template<class... Args>
struct Derived : public AbstractBase
{
virtual void PrintMe() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

template<class... Args>
AbstractBase *SelectInstance()
{
return new Derived<Args...>();
}

template<class Func, class... UnpackedArgs>
AbstractBase *SelectInstance(Func func)
{
if (func())
return SelectInstance<float, UnpackedArgs...>();
else
return SelectInstance<double, UnpackedArgs...>();
}

template<class Func, class... Args, class... UnpackedArgs>
AbstractBase *SelectInstance(Func func, Args... args)
{
if (func())
return SelectInstance<Args..., float, UnpackedArgs...>(args...);
else
return SelectInstance<Args..., double, UnpackedArgs...>(args...);
}

int main()
{
Options opts;
std::unique_ptr<AbstractBase> one(
SelectInstance(
std::bind(&Options::GetFirstParameter, &opts)
)
);
one->PrintMe();

std::unique_ptr<AbstractBase> two(
SelectInstance(
std::bind(&Options::GetFirstParameter, &opts),
std::bind(&Options::GetSecondParameter, &opts)
)
);
two->PrintMe();

// this one fails to compile!
std::unique_ptr<AbstractBase> three(
SelectInstance(
std::bind(&Options::GetFirstParameter, &opts),
std::bind(&Options::GetSecondParameter, &opts),
std::bind(&Options::GetThirdParameter, &opts)
)
);
three->PrintMe();
}

我可能错误地使用可变参数模板将仿函数转换为新的参数包。任何指导表示赞赏。

最佳答案

您尝试失败的原因是编译器无法判断您为什么提供了哪些参数。假设我们的函数类型是 A , B , 和 C为简单起见。初始调用是:

// Func = A, Args... = {B, C}, UnpackedArgs... = {}
AbstractBase *SelectInstance(Func func, Args... args)

从这里,我们调用 SelectInstance<Args..., float, UnpackedArgs...>(args...);也就是说,SelectInstance<B, C, float>(b, c);你的意思是:

// Func = B, Args... = {C}, UnpackedArgs... = {float}
AbstractBase *SelectInstance(Func func, Args... args)

但实际上参数包是贪婪的,什么都拿。 Args...采用您明确提供的每个后续类型参数。所以实际上那个调用被解释为:

// Func = B, Args... = {C, float}, UnpackedArgs... = {}
AbstractBase *SelectInstance(Func func, Args... args)

此函数采用三个参数(BCfloat),但您只传递两个参数(bc),因此出现错误。


要解决此问题,请翻转模板参数的顺序,将推导的参数放在第一位,将推导的参数放在最后。这样,您仍然可以使用模板推导来做正确的事情,甚至可以避免额外的重载:

template<class... Args>
AbstractBase *SelectInstance()
{
return new Derived<Args...>();
}

template<class... UnpackedArgs, class Func, class... Args>
AbstractBase *SelectInstance(Func func, Args... args)
{
if (func()) {
return SelectInstance<float, UnpackedArgs...>(args...);
}
else {
return SelectInstance<double, UnpackedArgs...>(args...);
}
}

这是有效的,因为现在您提供的所有参数都进入了 UnpackedArgs...和扣除数字 FuncArgs... - 这正是你想要的。

关于c++ - 使用多个参数包将运行时值转换为编译模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37121693/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com