在可变非类型模板中,模板列表中的每个值都有其 onw 类型:
template <typename T> void print_type(const T &) { std::cout << typeid(T).name() << '\n'; }
template <auto ... VALUE> void print_types_0() { (print_type(VALUE), ...); }
int main()
{
print_types_0<0u, 0ll>(); // prints "j x " (gcc 13.2.0)
}
所以,我希望下面的代码也能工作:
template <unsigned U> void vtemplate() { std::cout << "unsigned "; }
template <long long LL> void vtemplate() { std::cout << "long long "; }
template <auto ... VALUE> void print_types_1() { (vtemplate<VALUE>(), ...); }
int main()
{
print_types_1<1u, 1ll>(); // error!
}
但由于含糊不清而失败:
In instantiation of 'void print_types_1() [with auto ...VALUE = {1, 1}]':
required from here
error: call of overloaded 'vtemplate<1>()' is ambiguous
template <auto ... VALUE> void print_types_1() { (vtemplate<VALUE>(), ...); }
~~~~~~~~~~~~~~~~^~
note: candidate: 'void vtemplate() [with unsigned int U = 1]'
template <unsigned U> void vtemplate() { std::cout << "unsigned "; }
^~~~~~~~~
note: candidate: 'void vtemplate() [with long long int LL = 1]'
template <long long LL> void vtemplate() { std::cout << "long long "; }
^~~~~~~~~
我不确定它为什么会失败,我的猜测是不存在“模板值过载”之类的东西,即使
1u
和1ll
被正确地检测为unsigned
和long long
编译器中,两个值都可以转换为彼此的类型,因此两个 vtemplate
实例同样有效。另一方面,它适用于 print_types_0
,因为每个值都与函数参数更好匹配,并且没有歧义。
不确定我的解释是否正确,我期望
print_types_0
和 print_types_1
的行为几乎相同,有没有办法实现这个“value-template”重载?
您似乎正在描述一种情况,其中您有一个带有值模板参数的模板化函数(print_types_1),并且在使用不同类型的参数调用它时观察到意外的行为。您还将它与另一个行为不同的函数 (print_types_0) 进行比较。
在 C++ 中,当您有函数模板和多个重载时,编译器将尝试为所提供的参数找到最佳匹配。如果存在歧义或多个同样好的匹配,可能会导致编译错误。
根据您的描述,听起来您在重载解析中遇到了歧义,可能是由于 1u 和 1ll 都可以转换为彼此的类型。在这种情况下,编译器可能无法确定最佳匹配。
要解决此问题,您可以考虑使用 SFINAE(替换失败不是错误)技术或其他模板约束来指导编译器根据参数的类型特征选择正确的重载。
在没有看到实际代码的情况下,提供具体的解决方案有点困难。但是,如果您对实现“值模板”重载解析感兴趣,您可能需要研究 std::enable_if 和类型特征等技术,以根据参数的特征来约束模板重载。
如果您可以提供更具体的代码或描述您正在使用的模板参数和重载场景,我也许可以提供更有针对性的建议。