组合模板参数形成函数签名时无效的 void 参数

Invalid void parameter when combining template parameters to form a function signature

本文关键字:参数 无效 void 函数 组合      更新时间:2023-10-16

尝试获取两个回调的签名并生成使用其每个返回值的回调签名。

给定回调AB=> 生成F

例 1)A:int(char)B:double(bool)=> F: 双精度(整数)

例 2)答:void(char)乙:void(int)=> 女:空(空)

在实例化以void作为参数的回调时遇到了一个奇怪的编译器错误:

error: invalid parameter type ‘void’

有问题的代码

template<class Signature>
struct my_func;
template<class Ret, class... Args>
struct my_func<Ret(Args...)>
{};
template<class FuncA, class FuncB>
struct my_fwd;
template<class ORet, class... OArgs,
class Ret, class... Args>
struct my_fwd<
my_func<ORet(OArgs...)>,
my_func<Ret(Args...)>
>
{
my_func< ORet(Ret) > func;  // <--- error
};
int main(int, char *[])
{
my_func<void(int)> my3;  // (1)
my_func<void(void)> my4; // (2)
my_func<void()> my5;     // (3)
my_fwd< decltype(my3), my_func<void(char)> > fwd1; // (4)
my_fwd< decltype(my3), decltype(my4) > fwd2;       // (5)
return 0;
}

虽然my_func的实例化没有问题,void(1), (2), (3)my_fwd(4) (5)失败,我想了解原因。

解决方法?!

我找到了一种解决方法,通过专门针对Ret == voidmy_fwd

// with this specialization i can avoid the error
template<class ORet, class... OArgs,
class... Args>
struct my_fwd<
my_func<ORet(OArgs...)>,
my_func<void(Args...)>
>
{
my_func< ORet() > func;
};

问题

编译器尝试在内部实例化有什么区别

my_fwd< my_func<void(int)>, my_func<void(char)> >

->my_func<void(void)> func

main(): 中的手动版本my_func<void(void)> my4

void专用化是修复的正确方法吗? 选择? 我显然对专业化和代码重复并不感兴趣。

void作为模板参数与手动编写void (void)之间的区别在于,后者不会生成采用void参数的函数。将(void)列为函数的参数是一种语法结构,其含义与()相同。这是 C 的遗留问题,其中()表示"参数未指定",(void)表示"没有参数"。C++删除了未指定的情况,()在那里表示"没有参数"。

但是,模板实例化发生在语法处理之后很长时间,因此实际上尝试实例化函数的参数(T)T = void会导致错误。就像尝试声明一个函数需要(std::remove_reference<decltype(std::declval<void*>())>::type)(即void实际上拼写为一种类型)。

恐怕你能解决这个问题的唯一方法确实是专门针对void