模板参数类型 `void` 与显式使用 `void`
Template parameter type `void` vs explicit use of `void`
在下面的代码中,为什么模板函数 foo
的显式扩展编译失败,而 bar
的扩展编译成功?直播 link - https://godbolt.org/z/o8Ea49KEb
template <typename T1, typename T2>
T1 foo(T2) { T2(42); return T1{}; };
template <typename T1, typename T2>
T1 bar(void) { T2(42); return T1{}; };
int main()
{
foo<int, void>(); // fails
bar<int, void>(); // works
}
请注意,模板参数 T2
用于两个函数的主体,唯一的区别是 bar
的函数参数已被手动替换。
这个问题是在阅读 并试图简化问题后受到启发的。
参数列表 (void)
与空参数列表 ()
相同的规则在 C++ 标准中找到 [dcl.fct]/4:
A parameter list consisting of a single unnamed parameter of non-dependent type void
is equivalent to an empty parameter list. Except for this special case, a parameter shall not have type cv void
.
这个问题的重点是“non-dependent类型”。模板参数T
是type-dependent,所以不会触发规则。
我认为标准有这条规则,因为如果一个通常采用一个参数的模板函数突然变成一个 zero-parameter 函数,如果实例化碰巧使该参数类型为 void
。有了这个规则,我们就知道当一个模板被声明为一个参数时,它真的只有一个参数。
考虑以下几点:
template<typename T>
void foo(T) {}
void bar(void) {}
您假设 foo<void>
和 bar(void)
是等价的,但它们不是。 foo<T>
总是需要一个参数。所以foo<void>
等价于一个函数baz(void x)
。这不会编译,因为您不能拥有 void 类型的值。这与您收到的错误消息相同。
在函数签名中void bar(void)
括号中的空表示不同的东西:一个没有参数的函数。这是 C 的残余,不推荐。
函数 bar<void>(T)
和 baz(void x)
不能存在,因为它们都需要类型为 void
的值,而该值不存在。
模板函数的解决方案是为模板实例化非法的情况提供重载或特化。
template<typename T>
void foo(T) {} // one argument
void foo() {} // no arguments -> different signatures -> overload
template<typename T>
void bar() {} // no arguments
template<>
void bar<void> {} // still no arguments -> same signature -> specialisation
在下面的代码中,为什么模板函数 foo
的显式扩展编译失败,而 bar
的扩展编译成功?直播 link - https://godbolt.org/z/o8Ea49KEb
template <typename T1, typename T2>
T1 foo(T2) { T2(42); return T1{}; };
template <typename T1, typename T2>
T1 bar(void) { T2(42); return T1{}; };
int main()
{
foo<int, void>(); // fails
bar<int, void>(); // works
}
请注意,模板参数 T2
用于两个函数的主体,唯一的区别是 bar
的函数参数已被手动替换。
这个问题是在阅读
参数列表 (void)
与空参数列表 ()
相同的规则在 C++ 标准中找到 [dcl.fct]/4:
A parameter list consisting of a single unnamed parameter of non-dependent type
void
is equivalent to an empty parameter list. Except for this special case, a parameter shall not have type cvvoid
.
这个问题的重点是“non-dependent类型”。模板参数T
是type-dependent,所以不会触发规则。
我认为标准有这条规则,因为如果一个通常采用一个参数的模板函数突然变成一个 zero-parameter 函数,如果实例化碰巧使该参数类型为 void
。有了这个规则,我们就知道当一个模板被声明为一个参数时,它真的只有一个参数。
考虑以下几点:
template<typename T>
void foo(T) {}
void bar(void) {}
您假设 foo<void>
和 bar(void)
是等价的,但它们不是。 foo<T>
总是需要一个参数。所以foo<void>
等价于一个函数baz(void x)
。这不会编译,因为您不能拥有 void 类型的值。这与您收到的错误消息相同。
在函数签名中void bar(void)
括号中的空表示不同的东西:一个没有参数的函数。这是 C 的残余,不推荐。
函数 bar<void>(T)
和 baz(void x)
不能存在,因为它们都需要类型为 void
的值,而该值不存在。
模板函数的解决方案是为模板实例化非法的情况提供重载或特化。
template<typename T>
void foo(T) {} // one argument
void foo() {} // no arguments -> different signatures -> overload
template<typename T>
void bar() {} // no arguments
template<>
void bar<void> {} // still no arguments -> same signature -> specialisation